[
  {
    "path": ".cargo/config.toml",
    "content": "[target.'cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))']\nrunner = 'wasm-bindgen-test-runner'\n\n[target.'cfg(all(target_arch = \"wasm32\", target_os = \"wasi\"))']\nrunner = 'wasmtime -W unknown-imports-trap=y'\n\n[target.wasm32-unknown-unknown]\nrustflags = ['--cfg', 'getrandom_backend=\"wasm_js\"']\n"
  },
  {
    "path": ".firebaserc",
    "content": "{\n  \"projects\": {\n    \"default\": \"yew-rs\"\n  },\n  \"targets\": {\n    \"yew-rs\": {\n      \"hosting\": {\n        \"website\": [\n          \"yew-rs\"\n        ],\n        \"examples\": [\n          \"yew-rs-examples\"\n        ],\n        \"api\": [\n          \"yew-rs-api\"\n        ]\n      }\n    }\n  }\n}"
  },
  {
    "path": ".gitattributes",
    "content": "*.mdx linguist-detectable=false\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: yew\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve Yew\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Problem**\n<!-- A clear and concise description of what the bug is. -->\n\n**Steps To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Environment:**\n - Yew version: [e.g. v0.17, `master`]\n - Rust version: [e.g. 1.43.0, `nightly`]\n - Target, if relevant: [e.g. `wasm32-unknown-emscripten`]\n - Build tool, if relevant: [e.g. `wasm-pack`, `trunk`]\n - OS, if relevant: [e.g. MacOS]\n - Browser and version, if relevant: [e.g. Chrome v83]\n\n**Questionnaire**\n<!-- Developing Yew is a community effort! -->\n<!-- If you feel up to the challenge, please check one of the boxes below: -->\n- [ ] I'm interested in fixing this myself but don't know where to start\n- [ ] I would like to fix and I have a solution\n- [ ] I don't have time to fix this right now, but maybe later\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: Ask question\n    url: https://discord.gg/VQck8X4\n    about: Looking for a quick answer? Ask the community!\n  - name: Feature proposal\n    url: https://github.com/yewstack/yew/discussions/categories/ideas\n    about: Start a discussion for a feature you would like to see\n  - name: Issue with the Playground?\n    url: https://github.com/yewstack/yew-playground/issues/new\n    about: Open an issue on the yew-playground repository\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation.md",
    "content": "---\nname: Documentation\nabout: Report an issue relating to this project's documentation.\ntitle: ''\nlabels: documentation\nassignees: ''\n\n---\n\n<!-- Please only include one item in each issue! -->\n\nThis is about:\n- [ ] A typo \n- [ ] Inaccurate/misleading documentation (e.g. technically incorrect advice)\n- [ ] Undocumented code\n- [ ] Outdated documentation\n- [ ] Other\n\n**Problem**\n<!-- PLEASE INCLUDE A WAY TO LOCATE WHERE THE ISSUE IS, e.g.\n - A Github link to the text\n - The filename and line number\n - An excerpt from the docs that someone could use text search to locate\n-->\n<!-- What's wrong? -->\n\n<!-- EXAMPLES FOR TYPOS: -->\n<!-- e.g. There's a typo in the documentation about the `html!` macro. \nIt's in the word on line 14 column 5 in file \"...\" Here's a link to the text on Github \"https://github.com/...\" -->\n<!-- e.g. There's a typo in this sentence \"...\" on the webpage \"https://yew.rs/...\" -->\n\n<!-- EXAMPLES FOR MISLEADING DOCS -->\n<!-- e.g. The sentence \"...\" implies \"...\" but this is misleading because it might cause someone \nto think \"...\" which is wrong. -->\n\n<!-- EXAMPLES FOR MISSING DOCS -->\n<!-- e.g. There's no API documentation for the console service. -->\n<!-- e.g. There's no documentation on yew.rs for the console service. -->\n\n<!-- EXAMPLES FOR OUTDATED DOCS -->\n<!-- e.g. The documentation about the `html!` macro was written for a previous version of Yew and should be updated. -->\n\n**Details about the solution you'd like** _(Optional)_\n\n**Additional context** _(Optional)_\n<!-- e.g. examples of similar documentation which is of high quality -->\n\n**Questionaire** _(Optional)_\n- [ ] I'd like to write this documentation\n- [ ] I'd like to write this documentation but I'm not sure what's needed\n- [ ] I don't have time to add this right now, but maybe later\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "#### Description\n\n<!-- Please include a summary of the change. -->\n\nFixes #0000 <!-- replace with issue number or remove if not applicable -->\n\n#### Checklist\n\n<!-- For further details, please read CONTRIBUTING.md -->\n\n- [ ] I have reviewed my own code\n- [ ] I have added tests\n  <!-- If this is a bug fix, these tests will fail if the bug is present (to stop it from cropping up again) -->\n  <!-- If this is a feature, my tests prove that the feature works -->\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"cargo\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n      day: \"friday\"\n    open-pull-requests-limit: 2\n    groups:\n       cargo-deps:\n          patterns:\n            - \"*\"\n\n  - package-ecosystem: \"npm\"\n    directory: \"/website\"\n    schedule:\n      interval: \"monthly\"\n    target-branch: \"master\"\n    groups:\n       website-deps:\n          patterns:\n            - \"*\"\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n    target-branch: \"master\"\n"
  },
  {
    "path": ".github/workflows/auto-approve-maintainer-pr.yml",
    "content": "name: Auto approve\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - reopened\n      - synchronize\n      - ready_for_review\n      - review_requested\n\njobs:\n  auto-approve:\n    runs-on: ubuntu-latest\n    if: github.event.pull_request.draft == false\n    steps:\n      - name: Check if organization member\n        id: is_organization_member\n        uses: JamesSingleton/is-organization-member@1.1.0\n        with:\n          organization: \"yewstack\"\n          username: ${{ github.event.pull_request.user.login }}\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Auto approve\n        uses: hmarr/auto-approve-action@v4\n        if: ${{ steps.is_organization_member.outputs.result == 'true' || github.actor == 'dependabot[bot]' }}\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/benchmark-core.yml",
    "content": "name: Benchmark - core\n\non:\n  pull_request:\n    branches: [master]\n    paths:\n      - .github/workflows/benchmark-core.yml\n      - \"packages/yew/**\"\n      - \"tools/benchmark-core/**\"\n\njobs:\n  benchmark-core:\n    name: Benchmark - core\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout master\n        uses: actions/checkout@v6\n        with:\n          repository: \"yewstack/yew\"\n          ref: master\n          path: yew-master\n\n      - name: Checkout pull request\n        uses: actions/checkout@v6\n        with:\n          path: current-pr\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Restore Rust cache for yew packages\n        uses: Swatinem/rust-cache@v2\n        with:\n          workspaces: |\n            yew-master\n            current-pr\n\n      - name: Run pull request benchmark\n        working-directory: current-pr/tools/benchmark-core\n        run: cargo bench -q > ../output.log\n\n      - name: Run master benchmark\n        working-directory: yew-master/tools/benchmark-core\n        run: cargo bench -q > ../output.log\n\n      - name: Write Pull Request ID\n        run: |\n          echo \"${{ github.event.number }}\" > .PR_NUMBER\n\n      - name: Upload Artifact\n        uses: actions/upload-artifact@v7\n        with:\n          name: benchmark-core\n          include-hidden-files: true\n          path: |\n            .PR_NUMBER\n            yew-master/tools/output.log\n            current-pr/tools/output.log\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/benchmark-ssr.yml",
    "content": "name: Benchmark - SSR\n\non:\n  pull_request:\n    branches: [master]\n    paths:\n      - .github/workflows/benchmark-ssr.yml\n      - \"packages/yew/**\"\n      - \"packages/yew-macro/**\"\n      - \"packages/yew-router/**\"\n      - \"packages/yew-router-macro/**\"\n      - \"examples/function_router/**\"\n      - \"tools/benchmark-ssr/**\"\n\njobs:\n  benchmark-ssr:\n    name: Benchmark - SSR\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout master\n        uses: actions/checkout@v6\n        with:\n          repository: \"yewstack/yew\"\n          ref: master\n          path: yew-master\n\n      - name: Checkout pull request\n        uses: actions/checkout@v6\n        with:\n          path: current-pr\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n          targets: wasm32-unknown-unknown\n\n      - name: Restore Rust cache for yew packages\n        uses: Swatinem/rust-cache@v2\n        with:\n          workspaces: |\n            yew-master\n            current-pr\n\n      - name: Run pull request benchmark\n        working-directory: current-pr/tools/benchmark-ssr\n        run: cargo run --profile=bench -- --output-path ../output.json\n\n      - name: Run master benchmark\n        working-directory: yew-master/tools/benchmark-ssr\n        run: cargo run --profile=bench -- --output-path ../output.json\n\n      - name: Write Pull Request ID\n        run: |\n          echo \"${{ github.event.number }}\" > .PR_NUMBER\n\n      - name: Upload Artifact\n        uses: actions/upload-artifact@v7\n        with:\n          name: benchmark-ssr\n          include-hidden-files: true\n          path: |\n            .PR_NUMBER\n            yew-master/tools/output.json\n            current-pr/tools/output.json\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/benchmark.yml",
    "content": "name: Benchmark\n\non:\n  push:\n    paths-ignore:\n      - \"website/**\"\n    branches:\n      - master\n  pull_request:\n    paths-ignore:\n      - \"website/**\"\n    types: [labeled, synchronize, opened, reopened]\n\n# Cancel outstanding benchmarks on pull requests\n# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#example-using-a-fallback-value\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  benchmark:\n    if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'performance')\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          path: \"yew\"\n\n      - uses: actions/checkout@v6\n        with:\n          repository: krausest/js-framework-benchmark\n          path: \"js-framework-benchmark\"\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n          targets: wasm32-unknown-unknown\n\n      - name: Setup wasm-pack\n        uses: jetli/wasm-pack-action@v0.4.0\n\n      - name: Setup Node\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"lts/Jod\"\n          cache: \"npm\"\n          cache-dependency-path: js-framework-benchmark/package-lock.json\n\n      - name: Restore Rust cache for yew packages\n        uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n          workspaces: |\n            yew\n\n      - name: Setup chrome\n        id: setup-chrome\n        uses: browser-actions/setup-chrome@v2\n        with:\n          install-chromedriver: true\n\n      - name: Setup js-framework-benchmark\n        working-directory: js-framework-benchmark\n        run: |\n          npm ci\n          npm run install-server\n          npm run install-webdriver-ts\n\n      - name: Setup benchmark-struct benchmark\n        run: |\n          ls -lauh\n          rm *.js\n          rm *.wasm\n          echo \"STRUCT_BUILD_DIR=$PWD\" >> $GITHUB_ENV\n        working-directory: js-framework-benchmark/frameworks/keyed/yew/bundled-dist/\n\n      - name: Build benchmark-struct app\n        working-directory: yew/tools/benchmark-struct\n        run: |\n          RUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' wasm-pack build \\\n            --release \\\n            --target web \\\n            --no-typescript \\\n            --out-name js-framework-benchmark-yew \\\n            --out-dir $STRUCT_BUILD_DIR\n\n      - name: Show built benchmark-struct benchmark files\n        run: |\n          ls -lauh js-framework-benchmark/frameworks/keyed/yew/bundled-dist/\n\n      - name: Setup yew-hooks benchmark\n        run: |\n          ls -lauh\n          rm *.js\n          rm *.wasm\n          echo \"HOOKS_BUILD_DIR=$PWD\" >> $GITHUB_ENV\n        working-directory: js-framework-benchmark/frameworks/keyed/yew-hooks/bundled-dist/\n\n      - name: Build benchmark-hooks app\n        working-directory: yew/tools/benchmark-hooks\n        run: |\n          RUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' wasm-pack build \\\n            --release \\\n            --target web \\\n            --no-typescript \\\n            --out-name js-framework-benchmark-yew-hooks \\\n            --out-dir $HOOKS_BUILD_DIR\n\n      - name: Show built benchmark-hooks benchmark files\n        run: |\n          ls -lauh js-framework-benchmark/frameworks/keyed/yew-hooks/bundled-dist/\n\n      - name: Run js-framework-benchmark server\n        working-directory: js-framework-benchmark\n        run: |\n          npm start &\n          sleep 5\n\n      # https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md\n      - run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns\n\n      - name: Run js-framework-benchmark/webdriver-ts npm run bench\n        working-directory: js-framework-benchmark/webdriver-ts\n        run: xvfb-run npm run bench -- --framework keyed/yew keyed/yew-hooks --runner playwright --chromeBinary \"${{ steps.setup-chrome.outputs.chrome-path }}\"\n\n      - name: Transform results to be fit for display benchmark-action/github-action-benchmark@v1\n        run: |\n          mkdir artifacts/\n          jq -s . js-framework-benchmark/webdriver-ts/results/*.json | cargo run --manifest-path yew/Cargo.toml --release -p process-benchmark-results > artifacts/results.json\n          echo \"$EVENT_INFO\" > artifacts/.PR_INFO\n        env:\n          EVENT_INFO: ${{ toJSON(github.event) }}\n\n      - name: Upload result artifacts\n        uses: actions/upload-artifact@v7\n        with:\n          name: results\n          path: artifacts/\n          if-no-files-found: error\n          include-hidden-files: true\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/build-api-docs.yml",
    "content": "name: Build API Docs (Rustdoc)\non:\n  pull_request:\n    branches: [master]\n    paths:\n      - \"packages/**\"\n      - \"firebase.json\"\n      - \".github/workflows/*-docs.yml\"\n  push:\n    branches: [master]\n    paths:\n      - \"packages/**\"\n      - \"firebase.json\"\n      - \".github/workflows/*-docs.yml\"\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n          components: rust-docs\n\n      - name: Run cargo doc\n        env:\n          RUSTDOCFLAGS: --cfg documenting --html-before-content ./api-docs/before-content.html --extend-css ./api-docs/styles.css -Z unstable-options --enable-index-page\n        run: |\n          cargo doc \\\n            --no-deps \\\n            --all-features \\\n            -p yew \\\n            -p yew-macro \\\n            -p yew-router \\\n            -p yew-router-macro \\\n            -p yew-agent\n\n      - name: Move files in correct directory\n        run: |\n          mkdir -p api-docs/dist/next\n          cp -r target/doc/* api-docs/dist/next\n\n      - name: Upload build artifact\n        uses: actions/upload-artifact@v7\n        with:\n          name: api-docs\n          path: api-docs/\n          retention-days: 1\n\n      - if: github.event_name == 'pull_request'\n        name: Build pr info\n        run: |\n          echo \"${{ github.event.number }}\" > .PR_INFO\n\n      - if: github.event_name == 'pull_request'\n        name: Upload pr info\n        uses: actions/upload-artifact@v7\n        with:\n          name: pr-info\n          include-hidden-files: true\n          path: .PR_INFO\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/build-website.yml",
    "content": "name: Build website\non:\n  pull_request:\n    branches: [master]\n    paths:\n      - \"website/**\"\n      - \"firebase.json\"\n      - \".github/workflows/*-website.yml\"\n  push:\n    branches: [master]\n    paths:\n      - \"website/**\"\n      - \"firebase.json\"\n      - \".github/workflows/*-website.yml\"\n\njobs:\n  build:\n    name: Build Website\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup node\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"lts/Jod\"\n          package-manager-cache: false\n\n      - name: Install dependencies\n        run: |\n          cd website\n          npm ci\n\n      - name: Run prettier\n        id: fmt\n        continue-on-error: true\n        run: |\n          cd website\n          npm run fmt\n\n      - if: steps.fmt.outcome == 'failure'\n        run: |\n          cd website\n          npm run fmt:write\n          git diff\n          exit 1\n\n      - name: Check Translations\n        run: |\n          cd website\n          npm run check-translations\n\n      - name: Build\n        run: |\n          cd website\n          npm run build\n\n      - name: Upload build artifact\n        uses: actions/upload-artifact@v7\n        with:\n          name: website\n          path: website/build/\n          retention-days: 1\n\n      - if: github.event_name == 'pull_request'\n        name: Build pr info\n        run: |\n          echo \"${{ github.event.number }}\" > .PR_INFO\n\n      - if: github.event_name == 'pull_request'\n        name: Upload pr info\n        uses: actions/upload-artifact@v7\n        with:\n          name: pr-info\n          include-hidden-files: true\n          path: .PR_INFO\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/clippy.yml",
    "content": "name: Clippy\n\non:\n  pull_request:\n    paths:\n      - \".github/workflows/clippy.yml\"\n      - \"tools/**/*\"\n      - \"examples/**/*\"\n      - \"packages/**/*\"\n      - \"Cargo.toml\"\n      - \"Cargo.lock\"\n  push:\n    branches: [master]\n\njobs:\n  feature-soundness:\n    name: Feature Soundness\n    runs-on: ubuntu-latest\n    # if normal clippy doesn't succeed, do not try to lint feature soundness\n    needs: clippy\n\n    strategy:\n      fail-fast: false\n      matrix:\n        profile:\n          - dev\n          - release\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n          components: clippy\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - uses: taiki-e/install-action@cargo-hack\n\n      - name: Lint feature soundness\n        if: matrix.profile == 'dev'\n        run: >-\n          cargo hack clippy\n          -p yew -p yew-agent -p yew-router\n          --feature-powerset --no-dev-deps\n          --keep-going\n          -- -D warnings\n\n      - name: Lint feature soundness\n        if: matrix.profile == 'release'\n        run: >-\n          cargo hack clippy\n          -p yew -p yew-agent -p yew-router\n          --feature-powerset --no-dev-deps\n          --keep-going --release\n          -- -D warnings\n\n  clippy:\n    name: Clippy Workspace\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        toolchain:\n          - stable\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.toolchain }}\n          components: clippy\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Run clippy\n        run: |\n          cargo clippy \\\n            --all-targets \\\n            --all-features \\\n            --workspace \\\n            -- -D warnings\n"
  },
  {
    "path": ".github/workflows/fmt.yml",
    "content": "name: cargo fmt\non:\n  pull_request:\n    paths:\n      - \"**/*.rs\"\n  push:\n    branches: [master]\n    paths:\n      - \"**/*.rs\"\n\njobs:\n  format:\n    name: cargo fmt\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n          components: rustfmt\n\n      - name: Run fmt\n        run: cargo +nightly fmt --all -- --check\n"
  },
  {
    "path": ".github/workflows/inspect-next-changelogs.yml",
    "content": "name: Inspect next changelogs\n\npermissions:\n  contents: write\n\non:\n  workflow_dispatch:\n\njobs:\n  generate:\n    name: Generate changelogs\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Build changelog generator\n        run: cargo build --release -p changelog -- \n\n      - name: Read yew changelog in this step\n        shell: bash\n        run: ./target/release/changelog yew minor -t ${{ secrets.GITHUB_TOKEN }} -f \"$(pwd)/CHANGELOG.md\"\n\n      - name: Read yew-router changelog in this step\n        shell: bash\n        run: ./target/release/changelog yew-router minor -t ${{ secrets.GITHUB_TOKEN }} -f \"$(pwd)/CHANGELOG.md\"\n\n      - name: Read yew-agent changelog in this step\n        shell: bash\n        run: ./target/release/changelog yew-agent minor -t ${{ secrets.GITHUB_TOKEN }} -f \"$(pwd)/CHANGELOG.md\"\n"
  },
  {
    "path": ".github/workflows/main-checks.yml",
    "content": "name: Main Checks\n\non:\n  pull_request:\n    paths:\n      - \".github/workflows/main-checks.yml\"\n      - \"ci/**\"\n      - \"packages/**/*\"\n      - \"examples/**/*\"\n      - \"tools/**/*\"\n      - \"Cargo.toml\"\n      - \"Cargo.lock\"\n  push:\n    branches: [master]\n\njobs:\n  spell_check:\n    name: spellcheck\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - name: Check spelling\n        uses: crate-ci/typos@v1.44.0\n\n  doc_tests:\n    name: Documentation Tests\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n\n      # for wasm-bindgen-cli, always use stable rust\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n          targets: wasm32-unknown-unknown\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Install wasm-bindgen-cli\n        shell: bash\n        run: ./ci/install-wasm-bindgen-cli.sh\n\n      - uses: browser-actions/setup-geckodriver@latest\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n      - uses: nanasess/setup-chromedriver@v2\n\n      - name: Run doctest\n        run: |\n          ls packages | xargs -I {} \\\n            cargo test \\\n              -p {} \\\n              --doc \\\n              --all-features \\\n              --target wasm32-unknown-unknown\n\n  integration_tests:\n    name: Integration Tests on ${{ matrix.toolchain }}\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        toolchain:\n          - 1.84.0\n          - stable\n\n    steps:\n      - uses: actions/checkout@v6\n\n      # for wasm-bindgen-cli, always use stable rust\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.toolchain }}\n          targets: wasm32-unknown-unknown\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Install wasm-bindgen-cli\n        shell: bash\n        run: ./ci/install-wasm-bindgen-cli.sh\n\n      - uses: browser-actions/setup-geckodriver@latest\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: nanasess/setup-chromedriver@v2\n\n      - name: Run tests - yew\n        run: |\n          cd packages/yew\n          CHROMEDRIVER=$(which chromedriver) cargo test --features csr,hydration,ssr,test --target wasm32-unknown-unknown\n          GECKODRIVER=$(which geckodriver) cargo test --features csr,hydration,ssr,test --target wasm32-unknown-unknown\n\n      - name: Run tests - yew-router\n        run: |\n          cd packages/yew-router\n          CHROMEDRIVER=$(which chromedriver) cargo test --target wasm32-unknown-unknown\n          GECKODRIVER=$(which geckodriver) cargo test --target wasm32-unknown-unknown\n\n  unit_tests:\n    name: Unit Tests on ${{ matrix.toolchain }}\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        toolchain:\n          - 1.84.0\n          - stable\n          - nightly\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.toolchain }}\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Run native tests\n        env:\n          # workaround for lack of ternary operator\n          # see https://github.com/orgs/community/discussions/25725\n          RUSTFLAGS: ${{ matrix.toolchain == 'nightly' && '--cfg nightly_yew' || '' }}\n        run: |\n          if [[ \"${{ matrix.toolchain }}\" == \"1.84.0\" ]]; then\n            cargo test --all-targets -p yew-agent -p yew-agent-macro -p yew-router\n          else\n            ls packages | grep -v \"^yew$\" | xargs -I {} cargo test --all-targets -p {}\n          fi\n\n      - name: Run native tests for yew\n        env:\n          # workaround for lack of ternary operator\n          # see https://github.com/orgs/community/discussions/25725\n          RUSTFLAGS: ${{ matrix.toolchain == 'nightly' && '--cfg nightly_yew' || '' }}\n        run: cargo test -p yew --all-features\n\n  test-lints:\n    name: Test lints on nightly\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Run tests\n        env:\n          RUSTFLAGS: --cfg nightly_yew --cfg yew_lints\n        run: cargo test -p yew-macro test_html_lints\n\n  macro_tests_discovery:\n    name: Discover macro tests\n    runs-on: ubuntu-latest\n    outputs:\n      matrix: ${{ steps.discover.outputs.matrix }}\n    steps:\n      - uses: actions/checkout@v6\n      - id: discover\n        run: |\n          matrix=$(\n            find packages/*/tests -name '*_test.rs' ! -name 'html_lints_test.rs' -printf '%h/%f\\n' \\\n              | while IFS= read -r path; do\n                  pkg=$(echo \"$path\" | cut -d/ -f2)\n                  test=$(basename \"$path\" .rs)\n                  printf '{\"package\":\"%s\",\"test\":\"%s\"}\\n' \"$pkg\" \"$test\"\n                done \\\n              | jq -sc '{include: .}'\n          )\n          echo \"matrix=$matrix\" >> \"$GITHUB_OUTPUT\"\n\n  macro_tests:\n    name: Macro Tests (${{ matrix.test }})\n    needs: macro_tests_discovery\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix: ${{ fromJson(needs.macro_tests_discovery.outputs.matrix) }}\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: 1.84.0\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Run ${{ matrix.test }}\n        run: cargo test -p ${{ matrix.package }} --test ${{ matrix.test }}\n\n  unit_tests_wasi:\n    name: Unit Tests (WASI) on ${{ matrix.toolchain }}\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        toolchain:\n          - stable\n          - nightly\n\n    steps:\n      - uses: actions/checkout@v6\n      - uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.toolchain }}\n          target: wasm32-wasip1\n\n      - name: Install wasmtime\n        run: |\n          wget https://github.com/bytecodealliance/wasmtime/releases/download/v24.0.0/wasmtime-v24.0.0-x86_64-linux.tar.xz\n          tar xf wasmtime-v24.0.0-x86_64-linux.tar.xz\n          mv wasmtime-v24.0.0-x86_64-linux/wasmtime ~/wasmtime\n          rm -rf wasmtime-v24.0.0-x86_64-linux.tar.xz wasmtime-v24.0.0-x86_64-linux\n          chmod +x ~/wasmtime\n          mv ~/wasmtime /usr/local/bin\n          source ~/.bashrc\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Run WASI tests for yew\n        run: |\n          RUST_LOG=info\n          cargo test --features ssr,hydration,test --target wasm32-wasip1 -p yew\n\n  example-runnable-tests-on-wasi:\n    name: Example Runnable Tests on WASI\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        package:\n          - wasi_ssr_module\n        toolchain:\n          - stable\n          - nightly\n    steps:\n      - uses: actions/checkout@v6\n      - uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.toolchain }}\n          target: wasm32-wasip1\n\n      - name: Install wasmtime\n        run: |\n          wget https://github.com/bytecodealliance/wasmtime/releases/download/v24.0.0/wasmtime-v24.0.0-x86_64-linux.tar.xz\n          tar xf wasmtime-v24.0.0-x86_64-linux.tar.xz\n          mv wasmtime-v24.0.0-x86_64-linux/wasmtime ~/wasmtime\n          rm -rf wasmtime-v24.0.0-x86_64-linux.tar.xz wasmtime-v24.0.0-x86_64-linux\n          chmod +x ~/wasmtime\n          mv ~/wasmtime /usr/local/bin\n          source ~/.bashrc\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Build and run ${{ matrix.package }}\n        run: |\n          cargo build --target wasm32-wasip1 -p ${{ matrix.package }}\n          wasmtime -W unknown-imports-trap=y target/wasm32-wasip1/debug/${{ matrix.package }}.wasm\n\n  ssr_e2e_tests:\n    name: SSR E2E Tests (${{ matrix.example }})\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - example: ssr_router\n            server_bin: ssr_router_server\n            trunk_dir: examples/ssr_router\n          - example: simple_ssr\n            server_bin: simple_ssr_server\n            trunk_dir: examples/simple_ssr\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n          targets: wasm32-unknown-unknown\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - name: Install wasm-bindgen-cli\n        shell: bash\n        run: ./ci/install-wasm-bindgen-cli.sh\n\n      - name: Install trunk\n        uses: jetli/trunk-action@v0.5.1\n        with:\n          version: \"latest\"\n\n      - uses: browser-actions/setup-geckodriver@latest\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Run SSR E2E tests\n        run: |\n          GECKODRIVER=$(which geckodriver) cargo run -p ssr-e2e -- \\\n            --trunk-dir ${{ matrix.trunk_dir }} \\\n            --server-cmd \"cargo run -p ${{ matrix.example }} --bin ${{ matrix.server_bin }} --features ssr -- --dir ${{ matrix.trunk_dir }}/dist\" \\\n            --health-url http://127.0.0.1:8080/ \\\n            --test-pkg ${{ matrix.example }} \\\n            -- --target wasm32-unknown-unknown --test e2e\n"
  },
  {
    "path": ".github/workflows/post-benchmark-core.yml",
    "content": "name: Post Comment for Benchmark - core\n\non:\n  workflow_run:\n    workflows: [\"Benchmark - core\"]\n    types:\n      - completed\n\njobs:\n  post-benchmark-core:\n    name: Post Benchmark Comment on Pull Request\n    if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Download Repository\n        uses: actions/checkout@v6\n\n      - name: Download Artifact\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: benchmark-core\n          path: benchmark-core/\n\n      - name: Make pull request comment\n        run: |\n          cat - >>comment.txt <<EOF\n          ### Benchmark - core\n          #### Yew Master\n          \\`\\`\\`\n          EOF\n          cat benchmark-core/yew-master/tools/output.log >>comment.txt\n          cat - >>comment.txt <<EOF\n          \\`\\`\\`\n          #### Pull Request\n          \\`\\`\\`\n          EOF\n          cat benchmark-core/current-pr/tools/output.log >>comment.txt\n          cat - >>comment.txt <<EOF\n          \\`\\`\\`\n          EOF\n\n      - name: Read Pull Request ID\n        run: echo \"PR_NUMBER=$(cat benchmark-core/.PR_NUMBER)\" >> $GITHUB_ENV\n\n      - name: Post Comment\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const fs = require('fs');\n\n            const commentInfo = {\n              ...context.repo,\n              issue_number: ${{ env.PR_NUMBER }},\n            };\n\n            const comment = {\n              ...commentInfo,\n              body: fs.readFileSync(\"comment.txt\", 'utf-8'),\n            };\n\n            function isCommentByBot(comment) {\n              return comment.user.type === \"Bot\" && comment.body.includes(\"### Benchmark - core\");\n            }\n\n            let commentId = null;\n            const comments = (await github.rest.issues.listComments(commentInfo)).data;\n            for (let i = comments.length; i--; ) {\n              const c = comments[i];\n              if (isCommentByBot(c)) {\n                commentId = c.id;\n                break;\n              }\n            }\n\n            if (commentId) {\n              try {\n                await github.rest.issues.updateComment({\n                  ...context.repo,\n                  comment_id: commentId,\n                  body: comment.body,\n                });\n              } catch (e) {\n                commentId = null;\n              }\n            }\n\n            if (!commentId) {\n              await github.rest.issues.createComment(comment);\n            }\n"
  },
  {
    "path": ".github/workflows/post-benchmark-ssr.yml",
    "content": "name: Post Comment for Benchmark - SSR\n\non:\n  workflow_run:\n    workflows: [\"Benchmark - SSR\"]\n    types:\n      - completed\n\njobs:\n  post-benchmark-ssr:\n    name: Post Comment on Pull Request\n    if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Download Repository\n        uses: actions/checkout@v6\n\n      - name: Download Artifact\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: benchmark-ssr\n          path: benchmark-ssr/\n\n      - name: Make pull request comment\n        run: python3 ci/make_benchmark_ssr_cmt.py\n\n      - name: Read Pull Request ID\n        run: echo \"PR_NUMBER=$(cat benchmark-ssr/.PR_NUMBER)\" >> $GITHUB_ENV\n\n      - name: Post Comment\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const commentInfo = {\n              ...context.repo,\n              issue_number: ${{ env.PR_NUMBER }},\n            };\n\n            const comment = {\n              ...commentInfo,\n              body: JSON.parse(process.env.YEW_BENCH_SSR),\n            };\n\n            function isCommentByBot(comment) {\n              return comment.user.type === \"Bot\" && comment.body.includes(\"### Benchmark - SSR\");\n            }\n\n            let commentId = null;\n            const comments = (await github.rest.issues.listComments(commentInfo)).data;\n            for (let i = comments.length; i--; ) {\n              const c = comments[i];\n              if (isCommentByBot(c)) {\n                commentId = c.id;\n                break;\n              }\n            }\n\n            if (commentId) {\n              try {\n                await github.rest.issues.updateComment({\n                  ...context.repo,\n                  comment_id: commentId,\n                  body: comment.body,\n                });\n              } catch (e) {\n                commentId = null;\n              }\n            }\n\n            if (!commentId) {\n              await github.rest.issues.createComment(comment);\n            }\n"
  },
  {
    "path": ".github/workflows/post-benchmark.yml",
    "content": "name: \"Post benchmark results\"\n\non:\n  workflow_run:\n    workflows: [\"Benchmark\"]\n    types:\n      - completed\n\njobs:\n  post-benchmark-results:\n    if: github.event.workflow_run.conclusion == 'success'\n    runs-on: ubuntu-latest\n\n    steps:\n      # Checkout repo for the github-action-benchmark action\n      - uses: actions/checkout@v6\n\n      - name: Download result artifacts\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: results\n          path: ./artifacts\n\n      - name: Test for PR\n        uses: mathiasvr/command-output@v1\n        id: test-pr\n        with:\n          run: cat artifacts/.PR_INFO\n\n      # gh-pages branch is updated and pushed automatically with extracted benchmark data\n      - name: Store benchmark result\n        uses: benchmark-action/github-action-benchmark@v1\n        with:\n          name: \"Yew master branch benchmarks (Lower is better)\"\n          tool: \"customSmallerIsBetter\"\n          output-file-path: artifacts/results.json\n          gh-pages-branch: \"gh-pages\"\n          # Access token to deploy GitHub Pages branch\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          # Push and deploy GitHub pages branch automatically\n          alert-threshold: \"200%\"\n          alert-comment-cc-users: \"@yewstack/yew\"\n          # Only push when this is a non-pr commit that has been benchmarked, i.e. master\n          auto-push: ${{ fromJSON(steps.test-pr.outputs.stdout).number == '' }}\n          save-data-file: ${{ fromJSON(steps.test-pr.outputs.stdout).number == '' }}\n          # Enable job summary\n          summary-always: true\n          comment-always: true\n          ref: ${{ github.event.workflow_run.head_sha }}\n"
  },
  {
    "path": ".github/workflows/post-size-cmp.yml",
    "content": "name: Post Comment for Size Comparison\n\non:\n  workflow_run:\n    workflows: [\"Size Comparison\"]\n    types:\n      - completed\n\njobs:\n  post-size-cmp:\n    name: Post Size Comment on Pull Request\n    if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Download Repository\n        uses: actions/checkout@v6\n\n      - name: Download Artifact (master)\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: size-cmp-master-info\n          path: \"size-cmp-master-info/\"\n\n      - name: Download Artifact (PR)\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: size-cmp-pr-info\n          path: \"size-cmp-pr-info/\"\n\n      - name: Make pull request comment\n        run: python3 ci/make_example_size_cmt.py\n\n      - name: Post Comment\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const commentInfo = {\n              ...context.repo,\n              issue_number: ${{ env.PR_NUMBER }},\n            };\n\n            const comment = {\n              ...commentInfo,\n              body: JSON.parse(process.env.YEW_EXAMPLE_SIZES),\n            };\n\n            function isCommentByBot(comment) {\n              return comment.user.type === \"Bot\" && comment.body.includes(\"### Size Comparison\");\n            }\n\n            let commentId = null;\n            const comments = (await github.rest.issues.listComments(commentInfo)).data;\n            for (let i = comments.length; i--; ) {\n              const c = comments[i];\n              if (isCommentByBot(c)) {\n                commentId = c.id;\n                break;\n              }\n            }\n\n            if (commentId) {\n              try {\n                await github.rest.issues.updateComment({\n                  ...context.repo,\n                  comment_id: commentId,\n                  body: comment.body,\n                });\n              } catch (e) {\n                commentId = null;\n              }\n            }\n\n            if (!commentId) {\n              await github.rest.issues.createComment(comment);\n            }\n"
  },
  {
    "path": ".github/workflows/publish-api-docs.yml",
    "content": "name: Publish API Docs\non:\n  workflow_run:\n    workflows: [\"Build API Docs (Rustdoc)\"]\n    types:\n      - completed\n\njobs:\n  publish:\n    if: github.event.workflow_run.conclusion == 'success'\n    runs-on: ubuntu-latest\n\n    steps:\n      # need to checkout to get \"firebase.json\", \".firebaserc\"\n      - uses: actions/checkout@v6\n\n      - name: Download build artifact\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: api-docs\n          path: api-docs/\n\n      - if: github.event.workflow_run.event == 'pull_request'\n        name: Download pr info\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: pr-info\n          path: artifacts\n\n      - if: github.event.workflow_run.event == 'pull_request'\n        name: Apply pull request environment\n        run: |\n          pr_number=$(cat \"artifacts/.PR_INFO\")\n          if ! [[ \"$pr_number\" =~ ^[0-9]+$ ]]; then\n            echo \"pr number invalid\"\n            exit 1\n          fi\n          echo \"PR_NUMBER=$pr_number\" >> $GITHUB_ENV\n          echo \"PR_BRANCH=${{ github.event.workflow_run.head_branch }}\" >> $GITHUB_ENV\n          echo \"COMMIT_SHA=${{ github.event.workflow_run.head_sha }}\" >> $GITHUB_ENV\n\n      - if: github.event.workflow_run.event == 'push'\n        name: Apply push environment\n        run: |\n          echo \"CHANNEL_ID=live\" >> $GITHUB_ENV\n\n      - name: Deploy to Firebase\n        uses: siku2/action-hosting-deploy@v1\n        with:\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          firebaseToken: \"${{ secrets.FIREBASE_TOKEN }}\"\n          targets: api\n          channelId: \"${{ env.CHANNEL_ID }}\"\n          # link to the next version because that's what we care about\n          commentURLPath: \"/next/yew\"\n          # PR information\n          prNumber: \"${{ env.PR_NUMBER }}\"\n          prBranchName: \"${{ env.PR_BRANCH }}\"\n          commitSHA: \"${{ env.COMMIT_SHA }}\"\n"
  },
  {
    "path": ".github/workflows/publish-examples.yml",
    "content": "name: Publish Examples\non:\n  push:\n    branches: [master]\n    paths:\n      - 'tools/build-examples/**'\n      - 'examples/**'\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    env:\n      # leave empty for /\n      PUBLIC_URL_PREFIX: \"\"\n      RUSTUP_TOOLCHAIN: nightly\n\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n          targets: wasm32-unknown-unknown\n          components: rust-src\n\n      - uses: Swatinem/rust-cache@v2\n\n      - uses: jetli/trunk-action@v0.5.1\n        with:\n          version: 'latest'\n\n      - name: Get latest wasm-opt version\n        id: wasm-opt\n        uses: pozetroninc/github-action-get-latest-release@master\n        with:\n          repository: WebAssembly/binaryen\n          excludes: prerelease, draft\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build examples\n        run: cargo run -p build-examples --bin build-examples\n        env:\n          LATEST_WASM_OPT_VERSION: ${{ steps.wasm-opt.outputs.release }}\n\n      - name: Deploy to Firebase\n        uses: siku2/action-hosting-deploy@v1\n        with:\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          firebaseToken: \"${{ secrets.FIREBASE_TOKEN }}\"\n          channelId: live\n          targets: examples\n"
  },
  {
    "path": ".github/workflows/publish-website.yml",
    "content": "name: Publish website\non:\n  workflow_run:\n    workflows: [\"Build website\"]\n    types:\n      - completed\n\njobs:\n  publish:\n    if: github.event.workflow_run.conclusion == 'success'\n    runs-on: ubuntu-latest\n\n    steps:\n      # need to checkout to get \"firebase.json\", \".firebaserc\"\n      - uses: actions/checkout@v6\n\n      - name: Download build artifact\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: website\n          path: website/build\n\n      - if: github.event.workflow_run.event == 'pull_request'\n        name: Download pr info\n        uses: actions/download-artifact@v8\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          run-id: ${{ github.event.workflow_run.id }}\n          name: pr-info\n          path: artifacts\n\n      - if: github.event.workflow_run.event == 'pull_request'\n        name: Apply pull request environment\n        run: |\n          pr_number=$(cat \"artifacts/.PR_INFO\")\n          if ! [[ \"$pr_number\" =~ ^[0-9]+$ ]]; then\n            echo \"pr number invalid\"\n            exit 1\n          fi\n          echo \"PR_NUMBER=$pr_number\" >> $GITHUB_ENV\n          echo \"PR_BRANCH=${{ github.event.workflow_run.head_branch }}\" >> $GITHUB_ENV\n          echo \"COMMIT_SHA=${{ github.event.workflow_run.head_sha }}\" >> $GITHUB_ENV\n\n      - if: github.event.workflow_run.event == 'push'\n        name: Apply push environment\n        run: |\n          echo \"CHANNEL_ID=live\" >> $GITHUB_ENV\n\n      - name: Deploy to Firebase\n        uses: siku2/action-hosting-deploy@v1\n        with:\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          firebaseToken: \"${{ secrets.FIREBASE_TOKEN }}\"\n          targets: website\n          channelId: \"${{ env.CHANNEL_ID }}\"\n          # link to the next version because that's what we care about\n          commentURLPath: \"/docs/next\"\n          # PR information\n          prNumber: \"${{ env.PR_NUMBER }}\"\n          prBranchName: \"${{ env.PR_BRANCH }}\"\n          commitSHA: \"${{ env.COMMIT_SHA }}\"\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish yew package(s)\n\npermissions:\n  contents: write\n\non:\n  workflow_dispatch:\n    inputs:\n      level:\n        description: \"Version Level major|minor|patch\"\n        required: true\n        type: choice\n        options:\n          - patch\n          - minor\n          - major\n      packages:\n        description: \"List of packages to publish (space separated)\"\n        required: true\n        type: string\n\njobs:\n  publish:\n    name: Publish yew\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v6\n        with:\n          token: \"${{ secrets.YEWTEMPBOT_TOKEN }}\"\n          fetch-depth: 0\n\n      - name: Config Git\n        uses: oleksiyrudenko/gha-git-credentials@v2.1.2\n        with:\n          token: \"${{ secrets.YEWTEMPBOT_TOKEN }}\"\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Install cargo binary dependencies\n        uses: baptiste0928/cargo-install@v3\n        with:\n          crate: cargo-release\n          version: =1.1.1\n\n      - name: Cargo login\n        run: cargo login ${{ secrets.CRATES_IO_TOKEN }}\n\n      - name: Build command\n        shell: bash\n        env:\n          PACKAGES: ${{ github.event.inputs.packages }}\n        run: |\n          output=\"\"\n          for pkg in ${{ github.event.inputs.packages }}\n          do\n            output+=\"--package $pkg \" \n          done\n          echo \"pkg=$output\" >> $GITHUB_ENV\n\n      - name: Release yew\n        run: cargo release ${{ github.event.inputs.level }} --execute --no-confirm ${{ env.pkg }}\n\n      - name: Collect release info\n        id: releaseinfo\n        run: cargo run -p collect-release-info -- ${{ github.event.inputs.packages }}\n\n      - name: Create a version branch\n        if: github.event.inputs.level != 'patch'\n        uses: peterjgrainger/action-create-branch@v3.0.0\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          branch: ${{ steps.releaseinfo.outputs.version_branch }}\n\n      - name: Create releases\n        env:\n          GH_TOKEN: ${{ secrets.YEWTEMPBOT_TOKEN }}\n          RELEASES: ${{ steps.releaseinfo.outputs.releases }}\n        run: |\n          echo \"$RELEASES\" | jq -c '.[]' | while read -r release; do\n            tag=$(echo \"$release\" | jq -r '.tag')\n            name=$(echo \"$release\" | jq -r '.name')\n            body=$(echo \"$release\" | jq -r '.body')\n            gh release create \"$tag\" --title \"$name\" --notes \"$body\"\n          done\n"
  },
  {
    "path": ".github/workflows/size-cmp.yml",
    "content": "name: Size Comparison\n\non:\n  pull_request:\n    branches: [master]\n    paths:\n      - .github/workflows/size-cmp.yml\n      - \"ci/**\"\n      - \"packages/**\"\n      - \"examples/**\"\n      - \"Cargo.toml\"\n\njobs:\n  size-cmp:\n    name: Collect ${{ matrix.target }} Size\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        target: [\"master\", \"pr\"]\n\n    steps:\n      - name: Checkout master\n        uses: actions/checkout@v6\n        if: ${{ matrix.target == 'master' }}\n        with:\n          repository: \"yewstack/yew\"\n          ref: master\n\n      - name: Checkout pull request\n        uses: actions/checkout@v6\n        if: ${{ matrix.target == 'pr' }}\n\n      - name: Write Optimisation Flags\n        run: |\n          if [ -x ci/write-min-size-flags.sh ] ; then\n            ci/write-min-size-flags.sh\n          else\n            # this branch is a fallback used only for compatibility with earlier commits\n            # in the repository and other branches and can be removed in the future.\n            echo 'build-std = [\"std\", \"panic_abort\"]' >> .cargo/config.toml\n            echo '[build]' >> .cargo/config.toml\n            echo 'rustflags = [\"-Cpanic=abort\"]' >> .cargo/config.toml\n          fi\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n          components: rust-src\n          targets: wasm32-unknown-unknown\n\n      - name: Restore Rust cache\n        uses: Swatinem/rust-cache@v2\n\n      - name: Setup Trunk\n        uses: jetli/trunk-action@v0.5.1\n        with:\n          version: \"latest\"\n\n      - name: Get latest wasm-opt version\n        id: wasm-opt\n        uses: pozetroninc/github-action-get-latest-release@master\n        with:\n          repository: WebAssembly/binaryen\n          excludes: prerelease, draft\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build examples\n        run: cargo run -p build-examples --bin build-examples\n        env:\n          LATEST_WASM_OPT_VERSION: ${{ steps.wasm-opt.outputs.release }}\n\n      - name: Collect size information\n        run: python3 ci/collect_sizes.py\n        env:\n          ISSUE_NUMBER: ${{ github.event.number }}\n\n      - name: Upload Artifact\n        uses: actions/upload-artifact@v7\n        with:\n          name: size-cmp-${{ matrix.target }}-info\n          include-hidden-files: true\n          path: \".SIZE_CMP_INFO\"\n          retention-days: 1\n"
  },
  {
    "path": ".github/workflows/test-website.yml",
    "content": "name: \"Test Website\"\n\non:\n  pull_request:\n    paths:\n      - \".github/workflows/test-website.yml\"\n      - \"packages/**/*\"\n      - \"website/**/*\"\n  push:\n    branches: [master]\n\njobs:\n  website_tests:\n    name: Tests Website Snippets\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n\n      # for wasm-bindgen-cli, always use stable rust\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: stable\n\n      - name: Install wasm-bindgen-cli\n        shell: bash\n        run: ./ci/install-wasm-bindgen-cli.sh\n\n      - name: Setup toolchain\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly\n          targets: wasm32-unknown-unknown\n\n      - uses: Swatinem/rust-cache@v2\n        with:\n          save-if: ${{ github.ref == 'refs/heads/master' }}\n\n      - uses: browser-actions/setup-geckodriver@latest\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: nanasess/setup-chromedriver@v2\n\n      - name: Run website code snippet tests\n        run: cargo test -p website-test --target wasm32-unknown-unknown\n"
  },
  {
    "path": ".gitignore",
    "content": "target/\ndist/\n\n# backup files generated by rustfmt\n**/*.rs.bk\n\n# editor config files and directories\n*.iml\n/.idea/\n/.vscode/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## ✨ yew **0.23.0** *(2026-03-10)*\n\nbumping from 0.22 should require no code changes for most users.\n\n### 🚨 Breaking changes\n\n- Performance: use_reducer now skips re-rendering for the same Rc. [[@Pascal Sommer](https://github.com/Pascal-So), [#3945](https://github.com/yewstack/yew/pull/3945)]\n    NOTE: Whether this is breaking is arguable. It merely breaks the promise that a dispatch will always cause a re-render. For code that wishes to force re-render, [use_force_update](https://docs.rs/yew/latest/yew/functional/fn.use_force_update.html) helps. Please refer to [the migration guide](https://yew.rs/docs/next/migration-guides/yew/from-0_22_0-to-0_23_0) for details.\n\n### ⚡️ Features\n\n- `&str` and `String` can now be used for props of type `Option<Html>`. [[@Cashew](https://github.com/Casheeew), [#4020](https://github.com/yewstack/yew/pull/4020)]\n- Added a `scheduler::flush` function to reliably finish rendering. Useful in testing as a replacement for timeouts. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4044](https://github.com/yewstack/yew/pull/4044)]\n\n### 🛠 Fixes\n\n- No more broken child re-renders while setting parents' states. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4060](https://github.com/yewstack/yew/pull/4060)]\n- Ergonomics: Bare `None`s are now allowed for `Option<T>` props in the `html!` macro. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4021](https://github.com/yewstack/yew/pull/4021)]\n\n### ⚙️ Improvements\n\n- Yew's scheduler now yields to the main thread from time to time. This fix will make the web page more responsive and reduce warnings about long tasks in the console. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4033](https://github.com/yewstack/yew/pull/4033)]\n\n## ✨ yew-router **0.20.0** *(2026-03-10)*\n\nYew pinned to 0.23 now.\n\n### 🛠 Fixes\n\n- '/' is no longer wrongly encoded in wildcard route segments. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4056](https://github.com/yewstack/yew/pull/4056)]\n- Fixed a url corruption issue causing redirection to `/basename//basename` resulting in a 404. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4030](https://github.com/yewstack/yew/pull/4030)]\n\n## ✨ yew-agent **0.5.0** *(2026-03-10)*\n\nNo changes. \n\nYew pinned to 0.23 now.\n\n## ✨ yew **0.22.1** *(2026-02-28)*\n\n### 🛠 Fixes\n\n- Domslot hydration panic caused by suspension [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4003](https://github.com/yewstack/yew/pull/4003)]\n- Some `Option<T>` and `&T` types can be used as children again. e.g. `Option<AttrValue>` [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4005](https://github.com/yewstack/yew/pull/4005)]\n- Custom hooks now compiles in edition 2024. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3992](https://github.com/yewstack/yew/pull/3992)]\n- No more stale states in callbacks when multiple events fire rapidly. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3988](https://github.com/yewstack/yew/pull/3988)]\n- Fixed invisible svg issue on Chrome when included with `from_html_unchecked` [[@Jason Heard](https://github.com/101100), [#3970](https://github.com/yewstack/yew/pull/3970)]\n- Fixed documentation typo in introduction.mdx. [[@devfbe](https://github.com/devfbe), [#3417](https://github.com/yewstack/yew/pull/3417)]\n\n### ⚙️ Improvements\n- Improved SSR example with meta rendering. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4011](https://github.com/yewstack/yew/pull/4011)]\n- Replaced once_cell with std equivalents (LazyLock, OnceLock). [[@Siyuan Yan](https://github.com/Madoshakalaka), [#4010](https://github.com/yewstack/yew/pull/4010)]\n- Updated rust dependencies.\n\n## ✨ yew **0.22.0** *(2025-12-08)*\n\n\n### 🚨 Breaking changes\n\n - **MSRV raised to 1.84.0.** [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3900](https://github.com/yewstack/yew/pull/3900)]\n - Allow setting JsValue as properties. [[@Elina](https://github.com/ranile), [#3458](https://github.com/yewstack/yew/pull/3458)]\n - Remove deprecated `class=(...)` syntax. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3497](https://github.com/yewstack/yew/pull/3497)]\n - Remove ToHtml trait. [[@Elina](https://github.com/ranile), [#3453](https://github.com/yewstack/yew/pull/3453)]\n - Make `<textarea>` a void element (no children allowed anymore). [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3465](https://github.com/yewstack/yew/pull/3465)]\n\n### ⚡️ Features\n\n - **Add for-loops to `html!` macro.** [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3498](https://github.com/yewstack/yew/pull/3498)]\n - **Rename `#[function_component]` to `#[component]`.** [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3885](https://github.com/yewstack/yew/pull/3885)]\n - Add `serde` feature to yew. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3880](https://github.com/yewstack/yew/pull/3880)]\n - Add `use_ref` hook. [[@Alex Parrill](https://github.com/ColonelThirtyTwo), [#3548](https://github.com/yewstack/yew/pull/3548)]\n - Better ImplicitClone ergonomics. Fewer ampersands and stars needed in the `html!` macro. [[@Cecile Tonglet](https://github.com/cecton), [#3508](https://github.com/yewstack/yew/pull/3508), [#3431](https://github.com/yewstack/yew/pull/3431)] [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3892](https://github.com/yewstack/yew/pull/3878)]\n - Preserve camelCase for known SVG elements. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3875](https://github.com/yewstack/yew/pull/3875)]\n - Add `inert` to the boolean attributes list. [[@Tomoaki Kawada](https://github.com/kawadakk), [#3678](https://github.com/yewstack/yew/pull/3678)]\n - Namespace support for `VRaw`. [[@Finn Bear](https://github.com/finnbear), [#3640](https://github.com/yewstack/yew/pull/3640)]\n - `to_callback` methods and From impls to convert reducer dispatchers and state setters to callbacks. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3519](https://github.com/yewstack/yew/pull/3519)]\n - Allows converting `ChildrenRenderer<VNode>` and `VChild` to VList. [[@Muhammad Hamza](https://github.com/ranile), [#3444](https://github.com/yewstack/yew/pull/3444)]\n - Add `CallbackRef` that takes ref in argument instead of value. [[@Cecile Tonglet](https://github.com/cecton), [#3419](https://github.com/yewstack/yew/pull/3419)]\n - Allow import of layout_test into 3rd party crates. [[@rollo-b2c2](https://github.com/rollo-b2c2), [#3463](https://github.com/yewstack/yew/pull/3463)]\n - Add WASI support for server-side rendering. [[@langyo](https://github.com/langyo), [#3534](https://github.com/yewstack/yew/pull/3534)]\n - Make `UseFutureHandle` Clone. [[@Adam Steinberg](https://github.com/AdamSteinberg1), [#3529](https://github.com/yewstack/yew/pull/3529)]\n - Allow `Self` in prop fields. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3569](https://github.com/yewstack/yew/pull/3569)]\n - Allow boolean in `html!`. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3441](https://github.com/yewstack/yew/pull/3441)]\n\n### 🛠 Fixes\n\n - Fix panic when hydrating components with unstable render order. [[@WorldSEnder](https://github.com/WorldSEnder), [#3914](https://github.com/yewstack/yew/pull/3914)]\n - Fix hydration panic on camelCased elements. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3876](https://github.com/yewstack/yew/pull/3876)]\n - Fix autocompletion in html macro for rust-analyzer. [[@Moritz Hedtke](https://github.com/mohe2015), [#3829](https://github.com/yewstack/yew/pull/3829)]\n - Fix empty lists hydration failure when they were placed next to suspensions and other components. [[@WorldSEnder](https://github.com/WorldSEnder), [#3630](https://github.com/yewstack/yew/pull/3630)]\n - Silenced non-normalised element name warnings for SVG elements. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3769](https://github.com/yewstack/yew/pull/3769)]\n - Fixed inconsistent clone() requirement when passing Classes to HTML elements vs. components. [[@Siddhant Shekhar](https://github.com/sshekhar563), [#3931](https://github.com/yewstack/yew/pull/3931)]\n - Fix svg animation always starting immediately. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3892](https://github.com/yewstack/yew/pull/3892)]\n - Better diagnostics for byte literals in `html!`. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3441](https://github.com/yewstack/yew/pull/3441)]\n - Concise diagnostics for missing props. [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3873](https://github.com/yewstack/yew/pull/3873)]\n - Use the namespace when xmlns attributes are specified. [[@JasonCG](https://github.com/jasoncg), [#3629](https://github.com/yewstack/yew/pull/3629)]\n - Fix generic type missing errors in hooks. [[@Michael Meyer](https://github.com/Ichmed), [#3633](https://github.com/yewstack/yew/pull/3633)]\n - Better duplicate key diagnostics. [[@WorldSEnder](https://github.com/WorldSEnder), [#3785](https://github.com/yewstack/yew/pull/3785)]\n - Fix autocompletion in html macro for rust-analyzer. [[@Moritz Hedtke](https://github.com/mohe2015), [#3829](https://github.com/yewstack/yew/pull/3829)]\n - `#[hook]`: `clippy::multiple_bound_locations` lint no longer triggered. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3803](https://github.com/yewstack/yew/pull/3803)]\n\n### ⚙️ Improvements\n\n - Avoid unnecessary scheduling. [[@WorldSEnder](https://github.com/WorldSEnder), [#3935](https://github.com/yewstack/yew/pull/3935)]\n - Remove the dependency on `boolinator`. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3420](https://github.com/yewstack/yew/pull/3420)]\n - Avoid string copy for Key: From<String> implementation. [[@flumm](https://github.com/flumm), [#3858](https://github.com/yewstack/yew/pull/3858)]\n - Switch to tokise from tokio [[@Elina](https://github.com/ranile), [#3776](https://github.com/yewstack/yew/pull/3776)]\n - use_future_with: simplify code a bit by using read-only use_memo rather than use_state. [[@Léo Gaspard](https://github.com/Ekleog), [#3610](https://github.com/yewstack/yew/pull/3610)]\n\n### 📝 Documentation\n\n - website: modernise the Yew usage in the tutorial. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3882](https://github.com/yewstack/yew/pull/3882)]\n - website: make tutorial testable. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3879](https://github.com/yewstack/yew/pull/3879)]\n - fix the docs of use_prepared_state. [[@Tim Kurdov](https://github.com/its-the-shrimp), [#3881](https://github.com/yewstack/yew/pull/3881)]\n - Update tutorial placeholder image generator. [[@Nashwan Azhari](https://github.com/aznashwan), [#3830](https://github.com/yewstack/yew/pull/3830)]\n - Refactor(NavbarItem): improve readability and maintainability. [[@Brilliantkid](https://github.com/brilliantkid87), [#3763](https://github.com/yewstack/yew/pull/3763)]\n - Fix website search. [[@Muhammad Hamza](https://github.com/ranile), [#3522](https://github.com/yewstack/yew/pull/3522)]\n - Addition and improvements to example crates. [[@Oliver Bilbie](https://github.com/Oliver-Bilbie), [#3587](https://github.com/yewstack/yew/pull/3587)] [[@Astariul](https://github.com/astariul), [#3631](https://github.com/yewstack/yew/pull/3631)] [[@Yann Dirson](https://github.com/ydirson), [#3570](https://github.com/yewstack/yew/pull/3570)] [[@Cecile Tonglet](https://github.com/cecton), [#3505](https://github.com/yewstack/yew/pull/3505)] [[@Kaede Hoshikawa](https://github.com/futursolo), [#3436](https://github.com/yewstack/yew/pull/3436)] \n - Wording and typo fixes. [[@Waldir Pimenta](https://github.com/waldyrious), [#3754](https://github.com/yewstack/yew/pull/3754)] [[@Jupp56](https://github.com/Jupp56), [#3429](https://github.com/yewstack/yew/pull/3429)] [[@Flavio Moreira](https://github.com/fdvmoreira), [#3418](https://github.com/yewstack/yew/pull/3418)] [[@ronanM](https://github.com/ronanM), [#3413](https://github.com/yewstack/yew/pull/3413)] [[@Waldir Pimenta](https://github.com/waldyrious), [#3754](https://github.com/yewstack/yew/pull/3754)] [[@Damien Lachaume](https://github.com/dlachaume), [#3790](https://github.com/yewstack/yew/pull/3790)] [[@Edwin Amsler](https://github.com/RandomInsano), [#3788](https://github.com/yewstack/yew/pull/3788)] [[@Tushar GH](https://github.com/Tushar12222), [#3585](https://github.com/yewstack/yew/pull/3585)] [[@zhengwu](https://github.com/rockyzhengwu), [#3574](https://github.com/yewstack/yew/pull/3574)] [[@Raahim Fareed](https://github.com/raahimfareed), [#3539](https://github.com/yewstack/yew/pull/3539)] [[@gcmutator](https://github.com/gcmutator), [#3628](https://github.com/yewstack/yew/pull/3628)] [[@Raphael Martin Schindler](https://github.com/rmschindler), [#3605](https://github.com/yewstack/yew/pull/3605)] [[@Jonathan Picques](https://github.com/JonathanPicques), [#3448](https://github.com/yewstack/yew/pull/3448)] [[@Ikko Eltociear Ashimine](https://github.com/eltociear), [#3432](https://github.com/yewstack/yew/pull/3432)] [[@Daniel Sousa](https://github.com/moyeah), [#3425](https://github.com/yewstack/yew/pull/3425)]\n\n\n## ✨ yew-router **0.19.0** *(2025-12-08)*\n\n\n### ⚡️ Features\n\n - Introduce `FromQuery` and `IntoQuery` traits. [[@Robert Schütte](https://github.com/Roba1993), [#3565](https://github.com/yewstack/yew/pull/3565)]\n - Dynamic basename support. [[@Finn Bear](https://github.com/finnbear), [#3725](https://github.com/yewstack/yew/pull/3725)]\n\n### 🚨 Breaking changes\n\n - **MSRV raised to 1.84.0.** [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3900](https://github.com/yewstack/yew/pull/3900)]\n\n## ✨ yew-agent **0.4.0** *(2025-12-08)*\n\n\n### 🛠 Fixes\n\n - Fix calls of the disconnected method of on every render. [[@Shihpin Tseng](https://github.com/deftsp), [#3435](https://github.com/yewstack/yew/pull/3435)]\n\n### ⚡️ Features\n\n - **Support module type web worker.** [[@Luca Cappelletti](https://github.com/LucaCappelletti94), [#3859](https://github.com/yewstack/yew/pull/3859)]\n\n### 🚨 Breaking changes\n\n - **MSRV raised to 1.84.0.** [[@Siyuan Yan](https://github.com/Madoshakalaka), [#3900](https://github.com/yewstack/yew/pull/3900)]\n\n\n## ✨ yew **0.21.0** *(2023-09-23)*\n\n\n### 🛠 Fixes\n\n - Fix rust-analyzer non_camel_case_types warning. [[@Sean Bruton](https://github.com/Sean Bruton), [#3388](https://github.com/yewstack/yew/pull/3388)]\n - Fix incorrect text escaping during SSR. [[@Tim Kurdov](https://github.com/Tim Kurdov), [#3381](https://github.com/yewstack/yew/pull/3381)]\n - Fix top-level reconciliation in portals. [[@WorldSEnder](https://github.com/WorldSEnder), [#3020](https://github.com/yewstack/yew/pull/3020)]\n - Fix clippy::let_unit_value lint in propless components. [[@WorldSEnder](https://github.com/WorldSEnder), [#2970](https://github.com/yewstack/yew/pull/2970)]\n\n### ⚡️ Features\n\n - Updated the docs of `set_event_bubbling`. [[@Tim Kurdov](https://github.com/Tim Kurdov), [#3391](https://github.com/yewstack/yew/pull/3391)]\n - feat: support arrays for Classes/classes!(). [[@Pouriya](https://github.com/Pouriya), [#3393](https://github.com/yewstack/yew/pull/3393)]\n - Mark VNode as #[must_use]. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3387](https://github.com/yewstack/yew/pull/3387)]\n - Add `IntoPropValue` implementation to convert from `Cow`s to `AttrValue`. [[@Tim Kurdov](https://github.com/Tim Kurdov), [#3346](https://github.com/yewstack/yew/pull/3346)]\n - Remove compatibility code before 1.64. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3379](https://github.com/yewstack/yew/pull/3379)]\n - Keep checked attribute for elements without special handling. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3373](https://github.com/yewstack/yew/pull/3373)]\n - feat: implement hydration for vraw. [[@Dillen Meijboom](https://github.com/Dillen Meijboom), [#3245](https://github.com/yewstack/yew/pull/3245)]\n - Add webkitdirectory to the boolean attributes list. [[@Julius Lungys](https://github.com/Julius Lungys), [#3214](https://github.com/yewstack/yew/pull/3214)]\n - Incremental performance improvements to element creation. [[@Greg Johnston](https://github.com/Greg Johnston), [#3169](https://github.com/yewstack/yew/pull/3169)]\n - Make VList's children Rc'ed. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3050](https://github.com/yewstack/yew/pull/3050)]\n - Update dependencies. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3171](https://github.com/yewstack/yew/pull/3171)]\n - Pass string types to Html props. [[@Cecile Tonglet](https://github.com/Cecile Tonglet), [#2872](https://github.com/yewstack/yew/pull/2872)]\n - Implement an internal DomSlot for positioning instead of NodeRef. [[@WorldSEnder](https://github.com/WorldSEnder), [#3048](https://github.com/yewstack/yew/pull/3048)]\n - Prefer pop_first if it is available. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3084](https://github.com/yewstack/yew/pull/3084)]\n - Add method map() on Children to wrap easily. [[@Cecile Tonglet](https://github.com/Cecile Tonglet), [#3039](https://github.com/yewstack/yew/pull/3039)]\n - Reentrant event listeners. [[@WorldSEnder](https://github.com/WorldSEnder), [#3037](https://github.com/yewstack/yew/pull/3037)]\n - Add impl IntoIterator on &Classes. [[@Cecile Tonglet](https://github.com/Cecile Tonglet), [#3038](https://github.com/yewstack/yew/pull/3038)]\n - Assert there are no circular references. [[@WorldSEnder](https://github.com/WorldSEnder), [#3025](https://github.com/yewstack/yew/pull/3025)]\n### 🚨 Breaking changes\n\n - 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)]\n - Agent v2. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2773](https://github.com/yewstack/yew/pull/2773)]\n - Update signature of use_prepared_state/use_transitive_state. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3376](https://github.com/yewstack/yew/pull/3376)]\n - Make signature of use_future_with consistent. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3372](https://github.com/yewstack/yew/pull/3372)]\n - Allow any type to be used as Children (take 2). [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3289](https://github.com/yewstack/yew/pull/3289)]\n - Enable PartialEq for all virtual dom types. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3206](https://github.com/yewstack/yew/pull/3206)]\n - Pass hook dependencies as the first function argument. [[@Arniu Tseng](https://github.com/Arniu Tseng), [#2861](https://github.com/yewstack/yew/pull/2861)]\n - Make Classes cheap to clone. [[@Cecile Tonglet](https://github.com/Cecile Tonglet), [#3021](https://github.com/yewstack/yew/pull/3021)]\n\n## ✨ yew-router **0.18.0** *(2023-09-xx)*\n\n\n### ⚡️ Features\n\n- Update dependencies. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3171](https://github.com/yewstack/yew/pull/3171)]\n- Only handle \"normal\" clicks on <Link>s. [[@Kai Salmon](https://github.com/Kai Salmon), [#3056](https://github.com/yewstack/yew/pull/3056)]\n\n### 🚨 Breaking changes\n\n- Encode Path Parameters in `yew-router`. [[@Jedd Dryden](https://github.com/Jedd Dryden), [#3187](https://github.com/yewstack/yew/pull/3187)]\n- Pass hook dependencies as the first function argument. [[@Arniu Tseng](https://github.com/Arniu Tseng), [#2861](https://github.com/yewstack/yew/pull/2861)]\n\n## ✨ yew-agent **0.3.0** *(2023-09-xx)*\n\n\n### 🚨 Breaking changes\n\n- Agent v2. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2773](https://github.com/yewstack/yew/pull/2773)]\n\n\n## ✨ yew **0.20.0** *(2022-11-xx)*\n\n\n- ##### 🛠 Fixes\n\n  - Fix onsubmit event type in docs. [[@Allan](https://github.com/Allan), [#2926](https://github.com/yewstack/yew/pull/2926)]\n  - Fix issues with tuples in closing tag. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2886](https://github.com/yewstack/yew/pull/2886)]\n  - Fix checked property being reset. [[@WorldSEnder](https://github.com/WorldSEnder), [#2907](https://github.com/yewstack/yew/pull/2907)]\n  - Fix VList Stream in SSR. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2801](https://github.com/yewstack/yew/pull/2801)]\n  - Fixed `NodeRef` not being implicitly cloned with components. [[@wdcocq](https://github.com/wdcocq), [#2775](https://github.com/yewstack/yew/pull/2775)]\n  - Attributes: Fix apply_diff_index_maps. [[@Dietmar Maurer](https://github.com/Dietmar Maurer), [#2653](https://github.com/yewstack/yew/pull/2653)]\n  - Fix bubbling of events originating in shadow dom. [[@WorldSEnder](https://github.com/WorldSEnder), [#2627](https://github.com/yewstack/yew/pull/2627)]\n  - Fix some Hook edge cases. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2592](https://github.com/yewstack/yew/pull/2592)]\n  - Fix issue with node refs and hydration. [[@WorldSEnder](https://github.com/WorldSEnder), [#2597](https://github.com/yewstack/yew/pull/2597)]\n  - Fix macro hygiene issues. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2585](https://github.com/yewstack/yew/pull/2585)]\n  - Fix casing of dynamic tags. [[@WorldSEnder](https://github.com/WorldSEnder), [#2578](https://github.com/yewstack/yew/pull/2578)]\n  - Automatically convert closure to callback for component properties. [[@Finn Bear](https://github.com/Finn Bear), [#2554](https://github.com/yewstack/yew/pull/2554)]\n  - Fix a problem with NodeRefs and VTags, ref. [[@WorldSEnder](https://github.com/WorldSEnder), [#2279](https://github.com/yewstack/yew/pull/2279)]\n  - Fix defaulted type parameter.. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2284](https://github.com/yewstack/yew/pull/2284)]\n  - Use Ref::filter_map if rustc is later than 1.63. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2904](https://github.com/yewstack/yew/pull/2904)]\n  - Evaluate props in the order they're defined. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2887](https://github.com/yewstack/yew/pull/2887)]\n  - Context: Avoid storing a copy of children. [[@Dietmar Maurer](https://github.com/Dietmar Maurer), [#2885](https://github.com/yewstack/yew/pull/2885)]\n  - Various improvements to Classes, oriented around reducing allocations. [[@Nathan West](https://github.com/Nathan West), [#2870](https://github.com/yewstack/yew/pull/2870)]\n  - Resume Suspension upon unmount. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2874](https://github.com/yewstack/yew/pull/2874)]\n  - Make fn update() re-render the component by default. [[@Cecile Tonglet](https://github.com/Cecile Tonglet), [#2786](https://github.com/yewstack/yew/pull/2786)]\n  - Do not detach child elements if parent element is about to be detached. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2420](https://github.com/yewstack/yew/pull/2420)]\n  - remove some unsafes by using atomics. [[@WorldSEnder](https://github.com/WorldSEnder), [#2186](https://github.com/yewstack/yew/pull/2186)]\n  - `use_prepared_state` & `use_transitive_state`. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2650](https://github.com/yewstack/yew/pull/2650)]\n  - Silence some warnings from derive(Properties). [[@WorldSEnder](https://github.com/WorldSEnder), [#2266](https://github.com/yewstack/yew/pull/2266)]\n  - onsubmit should be a SubmitEvent. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2816](https://github.com/yewstack/yew/pull/2816)]\n\n- ##### ⚡️ Features\n\n  - Add VNode::from_html_unchecked. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2842](https://github.com/yewstack/yew/pull/2842)]\n  - Make Yew lints opt-in. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2882](https://github.com/yewstack/yew/pull/2882)]\n  - Allow skipping a callback when reforming. [[@Jens Reimann](https://github.com/Jens Reimann), [#2864](https://github.com/yewstack/yew/pull/2864)]\n  - Polled SSR Stream. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2824](https://github.com/yewstack/yew/pull/2824)]\n  - Add send_stream method for Scope. [[@laizy](https://github.com/laizy), [#2619](https://github.com/yewstack/yew/pull/2619)]\n  - Allow functions returning unit in `use_effect`. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2849](https://github.com/yewstack/yew/pull/2849)]\n  - Configurable Runtime. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2772](https://github.com/yewstack/yew/pull/2772)]\n  - Pinned Channels. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2811](https://github.com/yewstack/yew/pull/2811)]\n  - Bind to properties instead of attributes by default. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2819](https://github.com/yewstack/yew/pull/2819)]\n  - Convert nightly from a feature flag to a compiler flag. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2827](https://github.com/yewstack/yew/pull/2827)]\n  - Reduce SSR Buffers in VList. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2826](https://github.com/yewstack/yew/pull/2826)]\n  - Allow keywords after dash in element and attribute names. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2820](https://github.com/yewstack/yew/pull/2820)]\n  - Replace custom logging by tracing. [[@WorldSEnder](https://github.com/WorldSEnder), [#2814](https://github.com/yewstack/yew/pull/2814)]\n  - Implement sleep and interval for Yew Platform. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2784](https://github.com/yewstack/yew/pull/2784)]\n  - Remove component NodeRef. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2783](https://github.com/yewstack/yew/pull/2783)]\n  - Prepared States dependency should be Reference Counted. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2769](https://github.com/yewstack/yew/pull/2769)]\n  - Document features automatically.. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2780](https://github.com/yewstack/yew/pull/2780)]\n  - Streamed SSR Response. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2697](https://github.com/yewstack/yew/pull/2697)]\n  - Nightly features. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2743](https://github.com/yewstack/yew/pull/2743)]\n  - Allow VNode props to be converted to Children.. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2749](https://github.com/yewstack/yew/pull/2749)]\n  - Redo derive(Properties), take 2. [[@WorldSEnder](https://github.com/WorldSEnder), [#2729](https://github.com/yewstack/yew/pull/2729)]\n  - `Callback::reform()` should return `Callback<T, OUT>`. [[@orzogc](https://github.com/orzogc), [#2719](https://github.com/yewstack/yew/pull/2719)]\n  - Span hygiene and editor UX. [[@WorldSEnder](https://github.com/WorldSEnder), [#2702](https://github.com/yewstack/yew/pull/2702)]\n  - Block props update during hydration. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2665](https://github.com/yewstack/yew/pull/2665)]\n  - Point to `callback_future` in `callback` docs. [[@Shadlock0133](https://github.com/Shadlock0133), [#2674](https://github.com/yewstack/yew/pull/2674)]\n  - Change access to VList children to a wrapper. [[@WorldSEnder](https://github.com/WorldSEnder), [#2673](https://github.com/yewstack/yew/pull/2673)]\n  - Partially undo #2673, different approach for the DerefMut impl of VList. [[@WorldSEnder](https://github.com/WorldSEnder), [#2692](https://github.com/yewstack/yew/pull/2692)]\n  - Rework a bunch of cfg(feature) flags to be more principled. [[@WorldSEnder](https://github.com/WorldSEnder), [#2666](https://github.com/yewstack/yew/pull/2666)]\n  - Delay Hydration second render until all assistive nodes have been removed. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2629](https://github.com/yewstack/yew/pull/2629)]\n  - Allow to consume deps in use_callback. [[@Jet Li](https://github.com/Jet Li), [#2617](https://github.com/yewstack/yew/pull/2617)]\n  - Add `use_future` hook to make consuming futures as suspense easier. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2609](https://github.com/yewstack/yew/pull/2609)]\n  - Add the ability to use non-literal string as attribute names. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2593](https://github.com/yewstack/yew/pull/2593)]\n  - Introduce a dedicated use_force_update hook. [[@WorldSEnder](https://github.com/WorldSEnder), [#2586](https://github.com/yewstack/yew/pull/2586)]\n  - Impl ImplicitClone for Rc<T> where T: Sized. [[@Nano](https://github.com/Nano), [#2594](https://github.com/yewstack/yew/pull/2594)]\n  - SSR Hydration. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2552](https://github.com/yewstack/yew/pull/2552)]\n  - Add use_callback hook. [[@Jet Li](https://github.com/Jet Li), [#2566](https://github.com/yewstack/yew/pull/2566)]\n  - Introduce additional information in SSR artifact to facilitate Hydration. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2540](https://github.com/yewstack/yew/pull/2540)]\n  - Scoped event handlers. [[@WorldSEnder](https://github.com/WorldSEnder), [#2510](https://github.com/yewstack/yew/pull/2510)]\n  - An ever Increasing Component ID. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2537](https://github.com/yewstack/yew/pull/2537)]\n  - Prevents Fallback UI from becoming suspended. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2532](https://github.com/yewstack/yew/pull/2532)]\n  - `#[cfg(feature = \"render\")]` and `yew::Renderer`. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2498](https://github.com/yewstack/yew/pull/2498)]\n  - Introduce explicit internal datastructures modeling dom state. [[@WorldSEnder](https://github.com/WorldSEnder), [#2330](https://github.com/yewstack/yew/pull/2330)]\n  - Improve AnyScope API. [[@Aaron Erhardt](https://github.com/Aaron Erhardt), [#2445](https://github.com/yewstack/yew/pull/2445)]\n  - Automatic Message Batching. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2421](https://github.com/yewstack/yew/pull/2421)]\n  - Add Other variant to the ListenerKind. [[@Alexander Mescheryakov](https://github.com/Alexander Mescheryakov), [#2417](https://github.com/yewstack/yew/pull/2417)]\n  - Function Components & Hooks V2. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2401](https://github.com/yewstack/yew/pull/2401)]\n  - Add ContextHandle in yew::prelude. [[@Anuvrat Singh](https://github.com/Anuvrat Singh), [#2372](https://github.com/yewstack/yew/pull/2372)]\n  - Separate scheduler rendered call from create and render. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2374](https://github.com/yewstack/yew/pull/2374)]\n  - Update to edition 2021. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2354](https://github.com/yewstack/yew/pull/2354)]\n  - Server-side Rendering (without hydration). [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2335](https://github.com/yewstack/yew/pull/2335)]\n  - Make BaseComponent Sealed.. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2359](https://github.com/yewstack/yew/pull/2359)]\n  - Remove start_app_as_body.. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2346](https://github.com/yewstack/yew/pull/2346)]\n  - Bump minimal supported rust version (MSRV) to 1.56. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2334](https://github.com/yewstack/yew/pull/2334)]\n  - Suspense Support. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2212](https://github.com/yewstack/yew/pull/2212)]\n  - make layout testing code public. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2310](https://github.com/yewstack/yew/pull/2310)]\n  - Refactor and simplify `Callback`. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2301](https://github.com/yewstack/yew/pull/2301)]\n  - Add pending event listener on the VTag. [[@Alexander Mescheryakov](https://github.com/Alexander Mescheryakov), [#2300](https://github.com/yewstack/yew/pull/2300)]\n  - constify VList::new. [[@Alexander Mescheryakov](https://github.com/Alexander Mescheryakov), [#2293](https://github.com/yewstack/yew/pull/2293)]\n  - Allow `function_component` creation based on function name. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2292](https://github.com/yewstack/yew/pull/2292)]\n  - Implement IntoPropValue for Rc<str>. [[@Zachary Stewart](https://github.com/Zachary Stewart), [#2285](https://github.com/yewstack/yew/pull/2285)]\n  - Raw field names in property structs. [[@WorldSEnder](https://github.com/WorldSEnder), [#2273](https://github.com/yewstack/yew/pull/2273)]\n\n## ✨ yew-router **0.17.0** *(2022-11-xx)*\n\n\n- ##### 🛠 Fixes\n\n  - Fix basename handling in router. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2297](https://github.com/yewstack/yew/pull/2297)]\n\n- ##### ⚡️ Features\n\n  - Simple `NodeRef` passing to `<Link>` for yew-router. [[@Athan Clark](https://github.com/Athan Clark), [#2877](https://github.com/yewstack/yew/pull/2877)]\n  - Make Switch to accept a closure as render function directly. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2659](https://github.com/yewstack/yew/pull/2659)]\n  - `#[cfg(feature = \"render\")]` and `yew::Renderer`. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2498](https://github.com/yewstack/yew/pull/2498)]\n  - Includes query parameters in rendered Link component. [[@Yuki Kodama](https://github.com/Yuki Kodama), [#2464](https://github.com/yewstack/yew/pull/2464)]\n  - Update to edition 2021. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2354](https://github.com/yewstack/yew/pull/2354)]\n  - Support named wildcards when deriving Routable.. [[@Jonathan Bailey](https://github.com/Jonathan Bailey), [#2345](https://github.com/yewstack/yew/pull/2345)]\n  - Add HashRouter, basename and use gloo-history. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2239](https://github.com/yewstack/yew/pull/2239)]\n\n\n## ✨ yew-agent **0.2.0** *(2022-11-xx)*\n\n\n- ##### ⚡️ Features\n\n  - add `use_bridge` docs. [[@Shrey Sudhir](https://github.com/Shrey Sudhir), [#2722](https://github.com/yewstack/yew/pull/2722)]\n  - Update to edition 2021. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2354](https://github.com/yewstack/yew/pull/2354)]\n  - Move yew-agent to gloo. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#2326](https://github.com/yewstack/yew/pull/2326)]\n  - Implement PrivateAgent. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2318](https://github.com/yewstack/yew/pull/2318)]\n  - Remove context & job agent. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2295](https://github.com/yewstack/yew/pull/2295)]\n\n## ✨ yew **0.19.0** *(2021-11-26)*\n\n\n- ##### 🛠 Fixes\n\n  - Attempt to fix recursion on display. [[@mibes](https://github.com/mibes), [#2149](https://github.com/yewstack/yew/pull/2149)]\n  - Fix default passive option. [[@mc1098](https://github.com/mc1098), [#2111](https://github.com/yewstack/yew/pull/2111)]\n  - Fix trybuild. [[@mc1098](https://github.com/mc1098), [#2103](https://github.com/yewstack/yew/pull/2103)]\n  - Fix event handler during capture phase. [[@mc1098](https://github.com/mc1098), [#2062](https://github.com/yewstack/yew/pull/2062)]\n  - Fix `VTag` reuse to reset ancestor `NodeRef`. [[@mc1098](https://github.com/mc1098), [#2030](https://github.com/yewstack/yew/pull/2030)]\n  - Fix IntoEventCallback over IntoPropValue. [[@mc1098](https://github.com/mc1098), [#2025](https://github.com/yewstack/yew/pull/2025)]\n  - Remove underscore prefix on fn parameters. [[@mc1098](https://github.com/mc1098), [#2010](https://github.com/yewstack/yew/pull/2010)]\n  - Fix rust-analyzer #[derive(Properties)] warnings. [[@KarlitosVII](https://github.com/KarlitosVII), [#2007](https://github.com/yewstack/yew/pull/2007)]\n  - Fix clippy lints from 1.54.0. [[@Xavientois](https://github.com/Xavientois), [#1976](https://github.com/yewstack/yew/pull/1976)]\n  - Fix scheduler main queue delay (#1953). [[@intendednull](https://github.com/intendednull), [#1954](https://github.com/yewstack/yew/pull/1954)]\n  - Fix case warning on derived properties. [[@nitnelave](https://github.com/nitnelave), [#1929](https://github.com/yewstack/yew/pull/1929)]\n  - yew-macro: fix inability to set the autoplay attribute. [[@bakape](https://github.com/bakape), [#1866](https://github.com/yewstack/yew/pull/1866)]\n  - Fix duplicate `with props` error messages.. [[@teymour-aldridge](https://github.com/teymour-aldridge), [#1730](https://github.com/yewstack/yew/pull/1730)]\n  - Remove extra braces in html_nested macro. [[@Madoshakalaka](https://github.com/Madoshakalaka), [#2169](https://github.com/yewstack/yew/pull/2169)]\n  - Remove unused punct field from props. [[@Xavientois](https://github.com/Xavientois), [#1969](https://github.com/yewstack/yew/pull/1969)]\n\n- ##### ⚡️ Features\n\n  - Check event bubbling cancellation at each step of propagation. [[@rjmac](https://github.com/rjmac), [#2191](https://github.com/yewstack/yew/pull/2191)]\n  - Add possibility to cancel bubbling. [[@voidpumpkin](https://github.com/voidpumpkin), [#2172](https://github.com/yewstack/yew/pull/2172)]\n  - Add the ability to add child nodes conditionally in `html!`. [[@cecton](https://github.com/cecton), [#1609](https://github.com/yewstack/yew/pull/1609)]\n  - Add basic lints to the HTML macro.. [[@teymour-aldridge](https://github.com/teymour-aldridge), [#1748](https://github.com/yewstack/yew/pull/1748)]\n  - Refactor use ref hooks. [[@mc1098](https://github.com/mc1098), [#2093](https://github.com/yewstack/yew/pull/2093)]\n  - Implementation of portals. [[@WorldSEnder](https://github.com/WorldSEnder), [#2147](https://github.com/yewstack/yew/pull/2147)]\n  - Allow Classes properties to be created from string literals. [[@jplatte](https://github.com/jplatte), [#2141](https://github.com/yewstack/yew/pull/2141)]\n  - Use functions from `gloo_utils` instead of re-implementing them. [[@hamza1311](https://github.com/hamza1311), [#2124](https://github.com/yewstack/yew/pull/2124)]\n  - Reliable `use_reducer` dispatch and `use_state` setter. [[@futursolo](https://github.com/futursolo), [#2126](https://github.com/yewstack/yew/pull/2126)]\n  - Add custom type for attribute values. [[@hamza1311](https://github.com/hamza1311), [#1994](https://github.com/yewstack/yew/pull/1994)]\n  - Remove trailing semicolon in macro used in expression position. [[@vrmiguel](https://github.com/vrmiguel), [#2127](https://github.com/yewstack/yew/pull/2127)]\n  - Add set_if_neq for UseStateHandle. [[@voidpumpkin](https://github.com/voidpumpkin), [#2109](https://github.com/yewstack/yew/pull/2109)]\n  - Add safe first_node fn. [[@mc1098](https://github.com/mc1098), [#2094](https://github.com/yewstack/yew/pull/2094)]\n  - impl PartialEq for `UseStateHandle` and `UseReducerHandle`. [[@hamza1311](https://github.com/hamza1311), [#2092](https://github.com/yewstack/yew/pull/2092)]\n  - Remove `web_sys` re-export. [[@mc1098](https://github.com/mc1098), [#2084](https://github.com/yewstack/yew/pull/2084)]\n  - Use into_prop_value to convert str prop to Option<String>. [[@Xavientois](https://github.com/Xavientois), [#2080](https://github.com/yewstack/yew/pull/2080)]\n  - Component lifecycle scheduler optimizations. [[@bakape](https://github.com/bakape), [#2065](https://github.com/yewstack/yew/pull/2065)]\n  - Update dependencies. [[@mc1098](https://github.com/mc1098), [#2064](https://github.com/yewstack/yew/pull/2064)]\n  - Add support for missing boolean attributes. [[@mc1098](https://github.com/mc1098), [#2051](https://github.com/yewstack/yew/pull/2051)]\n  - Add fully qualified primitives in proc macro. [[@mc1098](https://github.com/mc1098), [#2037](https://github.com/yewstack/yew/pull/2037)]\n  - Remove 'static lifetime from hook init function. [[@mc1098](https://github.com/mc1098), [#2039](https://github.com/yewstack/yew/pull/2039)]\n  - Add \"struct update\" syntax to pass props to component (`..props` instead of `with props`). [[@Xavientois](https://github.com/Xavientois), [#2024](https://github.com/yewstack/yew/pull/2024)]\n  - Add `no_implicit_prelude` to proc macro tests. [[@mc1098](https://github.com/mc1098), [#2033](https://github.com/yewstack/yew/pull/2033)]\n  - Dev/listener multiplexer. [[@bakape](https://github.com/bakape), [#1542](https://github.com/yewstack/yew/pull/1542)]\n  - Remove ShouldRender type alias. [[@mc1098](https://github.com/mc1098), [#2011](https://github.com/yewstack/yew/pull/2011)]\n  - Components v2 (2). [[@hamza1311](https://github.com/hamza1311), [#1961](https://github.com/yewstack/yew/pull/1961)]\n  - Remove InputData & ChangeData. [[@mc1098](https://github.com/mc1098), [#2000](https://github.com/yewstack/yew/pull/2000)]\n  - Support const generics in `#[derive(Properties)]`. [[@maciejhirsz](https://github.com/maciejhirsz), [#1978](https://github.com/yewstack/yew/pull/1978)]\n  - Add shorthand syntax for props. [[@Xavientois](https://github.com/Xavientois), [#1970](https://github.com/yewstack/yew/pull/1970)]\n  - Static attribute lists. [[@bakape](https://github.com/bakape), [#1962](https://github.com/yewstack/yew/pull/1962)]\n  - yew/vlist: optimize diffing and patching. [[@bakape](https://github.com/bakape), [#1555](https://github.com/yewstack/yew/pull/1555)]\n  - Add requirement for braces around most props. [[@Xavientois](https://github.com/Xavientois), [#1939](https://github.com/yewstack/yew/pull/1939)]\n  - Optimize VTag construction, memory footprint and patching. [[@bakape](https://github.com/bakape), [#1947](https://github.com/yewstack/yew/pull/1947)]\n  - Refactor and cleanup codebase. [[@hamza1311](https://github.com/hamza1311), [#1842](https://github.com/yewstack/yew/pull/1842)]\n  - Helper to build changelog. [[@cecton](https://github.com/cecton), [#1845](https://github.com/yewstack/yew/pull/1845)]\n  - Implicit optional attributes. [[@siku2](https://github.com/siku2), [#1637](https://github.com/yewstack/yew/pull/1637)]\n  - yew: reduce scheduler call indirection. [[@bakape](https://github.com/bakape), [#1903](https://github.com/yewstack/yew/pull/1903)]\n  - Change match statement to if. [[@Xavientois](https://github.com/Xavientois), [#1884](https://github.com/yewstack/yew/pull/1884)]\n  - Optimize vtag construction. [[@bakape](https://github.com/bakape), [#1867](https://github.com/yewstack/yew/pull/1867)]\n  - Apply Clippy lints.. [[@teymour-aldridge](https://github.com/teymour-aldridge), [#1863](https://github.com/yewstack/yew/pull/1863)]\n  - Change the app struct to be a real handle to an Yew app instance and make it possible to destroy a running app. [[@nicklaswj](https://github.com/nicklaswj), [#1825](https://github.com/yewstack/yew/pull/1825)]\n  - Bring context to standard components. [[@Diggsey](https://github.com/Diggsey), [#1835](https://github.com/yewstack/yew/pull/1835)]\n  - Upgraded Hook API (2). [[@hamza1311](https://github.com/hamza1311), [#1780](https://github.com/yewstack/yew/pull/1780)]\n  - Store hook state in a mutable scoped-TLS. [[@Diggsey](https://github.com/Diggsey), [#1831](https://github.com/yewstack/yew/pull/1831)]\n  - Remove unnecessary allocation from `AnyScope`. [[@Diggsey](https://github.com/Diggsey), [#1830](https://github.com/yewstack/yew/pull/1830)]\n  - Added missing licenses to Cargo.toml files and updated to use SPDX syntax. [[@jbg](https://github.com/jbg), [#1822](https://github.com/yewstack/yew/pull/1822)]\n  - Update Rust version for macro tests to 1.51 & enable const generics tests. [[@hamza1311](https://github.com/hamza1311), [#1801](https://github.com/yewstack/yew/pull/1801)]\n  - Allow the use of Rust keywords for element names. [[@siku2](https://github.com/siku2), [#1772](https://github.com/yewstack/yew/pull/1772)]\n  - Refactor html tag peeking. [[@lukechu10](https://github.com/lukechu10), [#1738](https://github.com/yewstack/yew/pull/1738)]\n  - Generic functional components. [[@lukechu10](https://github.com/lukechu10), [#1756](https://github.com/yewstack/yew/pull/1756)]\n  - Add support for the unit struct in Properties derive. [[@Xavientois](https://github.com/Xavientois), [#1752](https://github.com/yewstack/yew/pull/1752)]\n  - Rip out stdweb. [[@philip-peterson](https://github.com/philip-peterson), [#1697](https://github.com/yewstack/yew/pull/1697)]\n\n## ✨ yew-router **0.16.0** *(2021-11-26)*\n\n\n- ##### 🛠 Fixes\n\n  - Fix Some Router Behaviour. [[@futursolo](https://github.com/futursolo), [#2107](https://github.com/yewstack/yew/pull/2107)]\n  - Fix multiple field enum tokens. [[@mc1098](https://github.com/mc1098), [#1988](https://github.com/yewstack/yew/pull/1988)]\n  - Fix clippy lints from 1.54.0. [[@Xavientois](https://github.com/Xavientois), [#1976](https://github.com/yewstack/yew/pull/1976)]\n  - Fix router. [[@hamza1311](https://github.com/hamza1311), [#1856](https://github.com/yewstack/yew/pull/1856)]\n  - update nom 6.1.2 and fix compile errors.. [[@higumachan](https://github.com/higumachan), [#1806](https://github.com/yewstack/yew/pull/1806)]\n\n- ##### ⚡️ Features\n\n  - Add missing router docs: Redirect, Nested Router, and Path Segament capturing. [[@Madoshakalaka](https://github.com/Madoshakalaka), [#2192](https://github.com/yewstack/yew/pull/2192)]\n  - use base url for href of links. [[@WorldSEnder](https://github.com/WorldSEnder), [#2177](https://github.com/yewstack/yew/pull/2177)]\n  - Use functions from `gloo_utils` instead of re-implementing them. [[@hamza1311](https://github.com/hamza1311), [#2124](https://github.com/yewstack/yew/pull/2124)]\n  - Update Yew Router as per #2113. [[@futursolo](https://github.com/futursolo), [#2118](https://github.com/yewstack/yew/pull/2118)]\n  - Update dependencies. [[@mc1098](https://github.com/mc1098), [#2064](https://github.com/yewstack/yew/pull/2064)]\n  - Add \"replace route\" call as a companion to \"push route\". [[@rjmac](https://github.com/rjmac), [#2023](https://github.com/yewstack/yew/pull/2023)]\n  - Add shorthand syntax for props. [[@Xavientois](https://github.com/Xavientois), [#1970](https://github.com/yewstack/yew/pull/1970)]\n  - Add requirement for braces around most props. [[@Xavientois](https://github.com/Xavientois), [#1939](https://github.com/yewstack/yew/pull/1939)]\n  - Clean-up and optimize router a little bit. [[@hamza1311](https://github.com/hamza1311), [#1869](https://github.com/yewstack/yew/pull/1869)]\n  - Apply Clippy lints.. [[@teymour-aldridge](https://github.com/teymour-aldridge), [#1863](https://github.com/yewstack/yew/pull/1863)]\n  - Rewrite router. [[@hamza1311](https://github.com/hamza1311), [#1791](https://github.com/yewstack/yew/pull/1791)]\n  - Added missing licenses to Cargo.toml files and updated to use SPDX syntax. [[@jbg](https://github.com/jbg), [#1822](https://github.com/yewstack/yew/pull/1822)]\n  - Update Rust version for macro tests to 1.51 & enable const generics tests. [[@hamza1311](https://github.com/hamza1311), [#1801](https://github.com/yewstack/yew/pull/1801)]\n  - Add support for the unit struct in Properties derive. [[@Xavientois](https://github.com/Xavientois), [#1752](https://github.com/yewstack/yew/pull/1752)]\n\n## ✨ yew-agent **0.1.0** *(2021-11-26)*\n\n\n- ##### 🛠 Fixes\n\n  - Fix unmaintained anymap dependency. [[@mc1098](https://github.com/mc1098), [#2071](https://github.com/yewstack/yew/pull/2071)]\n  - Fix clippy lints from 1.54.0. [[@Xavientois](https://github.com/Xavientois), [#1976](https://github.com/yewstack/yew/pull/1976)]\n  - Fix crash in link to destroyed agents. [[@kristoff3r](https://github.com/kristoff3r), [#1827](https://github.com/yewstack/yew/pull/1827)]\n\n- ##### ⚡️ Features\n\n  - allow web worker resource to be relative. [[@astraw](https://github.com/astraw), [#2086](https://github.com/yewstack/yew/pull/2086)]\n  - `use_bridge` hook for agents. [[@futursolo](https://github.com/futursolo), [#2125](https://github.com/yewstack/yew/pull/2125)]\n  - Use functions from `gloo_utils` instead of re-implementing them. [[@hamza1311](https://github.com/hamza1311), [#2124](https://github.com/yewstack/yew/pull/2124)]\n  - yew-agent: add missing web-sys features. [[@astraw](https://github.com/astraw), [#2085](https://github.com/yewstack/yew/pull/2085)]\n  - Update dependencies. [[@mc1098](https://github.com/mc1098), [#2064](https://github.com/yewstack/yew/pull/2064)]\n  - Drop Private worker handler when bridge is dropped. [[@FrancisMurillo](https://github.com/FrancisMurillo), [#1944](https://github.com/yewstack/yew/pull/1944)]\n\n## ✨ yew **0.18.0** *(2021-05-15)*\n\n\n- ##### 🛠 Fixes\n\n  - Fix missing redirects. [[@siku2](https://github.com/siku2), [#1640](https://github.com/yewstack/yew/pull/1640)]\n  - Remove Drop bound from Task trait. [[@siku2](https://github.com/siku2), [#1627](https://github.com/yewstack/yew/pull/1627)]\n  - Enable std feature for indexmap. [[@jstarry](https://github.com/jstarry), [#1709](https://github.com/yewstack/yew/pull/1709)]\n\n- ##### ⚡️ Features\n\n  - Implicit optional attributes. [[@siku2](https://github.com/siku2), [#1637](https://github.com/yewstack/yew/pull/1637)]\n  - Added callback_future_once in yewtil.(#1712). [[@fraillt](https://github.com/fraillt), [#1696](https://github.com/yewstack/yew/pull/1696)]\n  - Added relevant examples section to the docs. [[@oOBoomberOo](https://github.com/oOBoomberOo), [#1695](https://github.com/yewstack/yew/pull/1695)]\n  - Added missing KeyboardService re-export. [[@SOF3](https://github.com/SOF3), [#1694](https://github.com/yewstack/yew/pull/1694)]\n  - Rename internal Agent structs to match Component. [[@jstarry](https://github.com/jstarry), [#1688](https://github.com/yewstack/yew/pull/1688)]\n  - Add discussion link to issue selector. [[@jstarry](https://github.com/jstarry), [#1674](https://github.com/yewstack/yew/pull/1674)]\n  - Update link to Material Design Components. [[@TapioT](https://github.com/TapioT), [#1662](https://github.com/yewstack/yew/pull/1662)]\n  - Extract Classes to a separate macro. [[@cecton](https://github.com/cecton), [#1601](https://github.com/yewstack/yew/pull/1601)]\n  - Improve the \"keyed_list\" example. [[@titaneric](https://github.com/titaneric), [#1650](https://github.com/yewstack/yew/pull/1650)]\n  - Add documentation for component children. [[@K4rakara](https://github.com/K4rakara), [#1616](https://github.com/yewstack/yew/pull/1616)]\n  - Add a macro for building properties outside of html!. [[@siku2](https://github.com/siku2), [#1599](https://github.com/yewstack/yew/pull/1599)]\n\n## ✨ yew-router **0.15.0** *(2021-05-15)*\n\n- ##### ⚡️ Features\n  - None\n- ##### 🛠 Fixes\n  - None\n- ##### 🚨 Breaking changes\n  - `RouterButton` now prevents default events per default @TheNeikos\n\n## ✨ yew **0.17.4** *(2020-10-18)*\n\n\n- ##### 🛠 Fixes\n\n  - Fixed a \"call stack exceeded\" panic that occurred if a `Component` was updated many times [[@jstarry], [#1624](https://github.com/yewstack/yew/pull/1624)]\n\n## ✨ yew **0.17.3** *(2020-08-16)*\n\n\n- ##### ⚡️ Features\n\n  - Added `prompt` function to `DialogService`. [[@teymour-aldridge], [#1350](https://github.com/yewstack/yew/pull/1350)]\n  - Implement `From<&[T]>` where `T: AsRef<str>` for `Classes`. [[@alexschrod], [#1448](https://github.com/yewstack/yew/pull/1448)]\n  - Added `batch_callback_once` to `ComponentLink`. [[@ctron], [#1463](https://github.com/yewstack/yew/pull/1463)]\n\n- ##### 🛠 Fixes\n\n  - Properties with default type params can now have `Properties` trait derived. [[@siku2], [#1408](https://github.com/yewstack/yew/pull/1408)]\n  - `html!`: Improved compile error messages for invalid list fragments. [[@siku2], [#1445](https://github.com/yewstack/yew/pull/1445)]\n  - Batch component updates are processed more efficiently. [[@bakape], [#1470](https://github.com/yewstack/yew/pull/1470)]\n\n## ✨ yew **0.17.2** *(2020-07-04)*\n\n\n- ##### ⚡️ Features\n\n  - `Key` now implements `Deref<Target = str>`. [[@faulesocke], [#1370](https://github.com/yewstack/yew/pull/1370)]\n\n- ##### 🛠 Fixes\n\n  - Uncontrolled input values are no cleared when component renders. [[@jstarry], [#1374](https://github.com/yewstack/yew/pull/1374)]\n  - Revert lazy rendering behavior introduced in `0.17.0`. Yew will render the component between each update. [[@jstarry], [#1373](https://github.com/yewstack/yew/pull/1373)]\n\n## ✨ yew **0.17.1** *(2020-07-01)*\n\n\n- ##### 🛠 Fixes\n\n  - Fixed regression where component `rendered` lifecycle method was called before children components finish rendering. [[@jstarry], [#1360](https://github.com/yewstack/yew/pull/1360)]\n\n## ✨ yew-router **0.14.0** *(2020-06-30)*\n\n- ##### ⚡️ Features\n  - None \n- ##### 🛠 Fixes\n  - None \n- ##### 🚨 Breaking changes\n  - The `unit_state` module has been removed. \n  - Bump `yew` version to `0.17`.\n\n## ✨ yew **0.17.0** *(2020-06-29)*\n\n\n- ##### ⚡️ Features\n\n  - Allow agents to send input messages to themselves. [[@mkawalec], [#1278](https://github.com/yewstack/yew/pull/1278)]\n  - Rendering performance has been improved by [~20%](http://static.yew.rs/v0.17-benchmarks.png). [[@jstarry], [#1296](https://github.com/yewstack/yew/pull/1296), [#1309](https://github.com/yewstack/yew/pull/1309)]\n  - `html!`: Elements can be specified with dynamic tag names. [[@siku2], [#1266](https://github.com/yewstack/yew/pull/1266)]\n\n      In order to specify a dynamic tag name, wrap an expression with `@{..}`:\n\n      ```rust\n      let tag_name = \"input\";\n      html! { <@{tag_name} value=\"Hello\" /> }\n      ```\n  - HTML button element `type` can now be specified (`\"submit\"`, `\"reset\"`, or `\"button\"`). [[@captain-yossarian], [#1033](https://github.com/yewstack/yew/pull/1033)]\n  - All global event listeners can be used as listeners (`onerror`, `onloadend`, and many more). [[@siku2], [#1244](https://github.com/yewstack/yew/pull/1242)]\n  - `PartialEq` is now implemented for `VChild` when properties also implement `PartialEq`. [[@kellpossible], [#1242](https://github.com/yewstack/yew/pull/1242)]\n  - Agent callbacks now accept `Into<Message>` to improve ergonomics. [[@totorigolo], [#1215](https://github.com/yewstack/yew/pull/1215)]\n  - Agents can now send messages to themselves. [[@totorigolo], [#1215](https://github.com/yewstack/yew/pull/1215)]\n\n- ##### 🛠 Fixes\n\n  - Bincode dependency version has been loosened `1.2.1` -> `1`. [[@jstarry], [#1349](https://github.com/yewstack/yew/pull/1349)]\n  - Keyed list ordering algorithm has been fixed. [[@totorigolo] and [@jstarry], [#1231](https://github.com/yewstack/yew/pull/1231)]\n  - `html!`: `key` and `ref` are no longer ignored for components with no properties. [[@jstarry], [#1338](https://github.com/yewstack/yew/pull/1338)]\n  - `html!`: List rendering behavior is consistent no matter which syntax is chosen. [[@siku2], [#1275](https://github.com/yewstack/yew/pull/1275)]\n\n      `html! { for node_list }` is now equivalent to `html! { node_list }` when `node_list` is a `Vec<VNode>`.\n\n  - `KeyboardService` events can now have default behavior prevented. [[@ghpu], [#1286](https://github.com/yewstack/yew/pull/1286)]\n  - Yew will check the current DOM `input` value before comparing with the desired value. [[@ShadoySV], [#1268](https://github.com/yewstack/yew/pull/1268)]\n  - `html!`: Void elements (`<br/>`, `<input />`) are no longer allowed to have children. [[@kaoet], [#1217](https://github.com/yewstack/yew/pull/1217)]\n  - Local agents no longer require `Input` and `Output` to implement `Serializable`. [[@mkawalec], [#1195](https://github.com/yewstack/yew/pull/1195)]\n\n- ##### 🚨 Breaking changes\n\n  - Renders are now done lazily and will not be executed until all updates have been processed. [[@jstarry], [#1309](https://github.com/yewstack/yew/pull/1309)]\n  - `ConsoleService`, `DialogService`, `IntervalService`, `RenderService`, `TimeoutService`, and `WebSocketService` methods are now static. [[@teymour-aldridge], [#1313](https://github.com/yewstack/yew/pull/1313)]\n  - `html!`: `Children` no longer implements `Renderable`. [[@siku2], [#1275](https://github.com/yewstack/yew/pull/1275)]\n\n      Replace instances of `self.props.children.render()` with `self.props.children.clone()`.\n\n  - Yew no longer stops propagation of events by default. [[@jstarry], [#1256](https://github.com/yewstack/yew/pull/1256)]\n\n      Event propagation is usually stopped when you have event listeners attached to nested elements and do not want the event to bubble up from where it was first captured. If your app has this behavior, you can stop propagation by calling `stop_propagation()` on the desired event.\n\n  - The `onsubmit` listener now uses `FocusEvent` instead `Event` when using `web-sys`. [[@siku2], [#1244](https://github.com/yewstack/yew/pull/1244)]\n  - The `onmousewheel` and `ontouchenter` listeners have been removed. [[@siku2], [#1244](https://github.com/yewstack/yew/pull/1244)]\n  - The `ondoubleclick` listener is now named `ondblclick`. [[@siku2], [#1244](https://github.com/yewstack/yew/pull/1244)]\n  - `FetchService` methods are now static. [[@teymour-aldridge], [#1235](https://github.com/yewstack/yew/pull/1235)]\n\n      Instead of `FetchService::new().fetch(..)` you should now use `FetchService::fetch(..)`\n\n  - The `send_message_batch` method has been removed from `AgentLink`. [[@totorigolo], [#1215](https://github.com/yewstack/yew/pull/1215)]\n  - Minimum supported rust version has been bumped from `1.40.0` to `1.42.0`. [[@mkawalec], [#1195](https://github.com/yewstack/yew/pull/1195)]\n  - Every agent `Reach` type is now generic. [[@mkawalec], [#1195](https://github.com/yewstack/yew/pull/1195)]\n\n      In order to fix your app, simply append `<Self>` to the reach:\n\n      `Reach = Context` -> `Reach = Context<Self>`\n  - Removed `Global` agent because it was never implemented. [[@jstarry], [#1202](https://github.com/yewstack/yew/pull/1202)]\n  - Reduced visibility of internal agent types that were not intended to be public. [[@jstarry], [#1202](https://github.com/yewstack/yew/pull/1202)]\n\n## ✨ yew **0.16.2** *(2020-05-14)*\n\n\n- ##### 🛠 Fixes\n\n  - Fixed regression where messages sent from `Component::create` were skipped. [[@jstarry], [#1225](https://github.com/yewstack/yew/pull/1225)]\n\n## ✨ yew **0.16.1** *(2020-05-14)*\n\n\n- ##### 🛠 Fixes\n\n  - Worker script is now loaded from absolute path. [[@domdir], [#1175](https://github.com/yewstack/yew/pull/1175)]\n  - Improved `html!` macro error messages. [[@teymour-aldridge], [#1192](https://github.com/yewstack/yew/pull/1192)], [[@kaoet], [#1219](https://github.com/yewstack/yew/pull/1219)]\n\n## ✨ yew-router **0.13.0** *(2020-05-12)*\n\n- ##### 🚨 Breaking changes\n  - Bump `yew` version to `0.16`.\n\n## ✨ yew **0.16** *(2020-05-09)*\n\n\n- ##### ⚡️ Features\n\n  - Added optional `id`, `class`, and `placeholder` properties to the `Select` component. [[@Stigjb], [#1187](https://github.com/yewstack/yew/pull/1187)]\n  - Re-export `web-sys` from Yew. This allows projects to use `web-sys` without adding it to their `Cargo.toml`. [[@D4nte], [#1176](https://github.com/yewstack/yew/pull/1176)]\n  - Added support for `Option` wrapped class names. [[@liquidblock], [#1085](https://github.com/yewstack/yew/pull/1085)]\n\n    The following code is now supported:\n    ```rust\n    let color: &Option<String> = &self.color;\n    html! { <div class=(\"btn\", color)></div> }\n    ```\n\n  - Added `get_parent` and `get_component` methods to `ComponentLink` to allow access to parent component state. [[@jstarry], [#1151](https://github.com/yewstack/yew/pull/1151)]\n\n- ##### 🛠 Fixes\n\n  - Fixed bug that caused html class attributes to be set to an empty string. [[@liquidblock], [#1085](https://github.com/yewstack/yew/pull/1085)]\n  - Fixed `Private` worker lifecycle event sending. [[@joaquindk], [#1146](https://github.com/yewstack/yew/pull/1146)]\n\n- ##### 🚨 Breaking changes\n\n  - Bumped minimum supported Rust version (MSRV) to 1.40.0. [[@jstarry], [#1152](https://github.com/yewstack/yew/pull/1152)]\n\n## ✨ yew-router **0.12.1** *(2020-04-26)*\n- ##### 🛠 Fixes\n  - Fix infinite rerender bug in 'Router' component. (Thanks @dancespiele)\n\n## ✨ yew **0.15** *(2020-04-25)*\n\n#### Attention!\n`yew` now uses `web-sys` by default. If your project uses `web-sys`, you can now drop the `\"web_sys\"` feature from your yew dependency.\nDon't worry `stdweb` users, we have created a new alias crate for y'all called `yew-stdweb`. In order to use it, update your `Cargo.toml` yew dependency to the following:\n\n```toml\nyew = { version = \"0.15\", package = \"yew-stdweb\" }\n```\n\n#### Dev Survey Results\nThank you to everyone that took the time to fill out the Yew Dev Survey! 🙇‍♂️\n\nResults have been posted here: https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D\n\n#### New Chatroom\nWe moved from Gitter to Discord! Join us: https://discord.gg/VQck8X4\n\n\n- ##### ⚡️ Features\n\n  - Add support for single use callbacks (useful for `TimeoutService`). [[@lukerandall], [#1125](https://github.com/yewstack/yew/pull/1125)]\n  - Updated scheduler to eagerly destroy components to avoid unnecessary renders. [[@jstarry], [#1072](https://github.com/yewstack/yew/pull/1072)]\n  - Add support `key` attribute to improve rendering performance. [[@mrh0057], [#1076](https://github.com/yewstack/yew/pull/1076)]\n\n- ##### 🛠 Fixes\n\n  - Split class names on whitespace when passed within `tuple` or `Vec`. [[@bryanjswift], [#1084](https://github.com/yewstack/yew/pull/1084)]\n\n- ##### 🚨 Breaking changes\n\n  - The `components` module has been moved out `yew` and into `yew-components`. [[@jstarry], [#1132](https://github.com/yewstack/yew/pull/1132)]\n  - Replaced `mounted` component lifecycle method with `rendered` which is called after each render. [[@jstarry], [#1072](https://github.com/yewstack/yew/pull/1072)]\n  - Components must now implement the `change` method (forgetting this was a very common issue). [[@jstarry], [#1071](https://github.com/yewstack/yew/pull/1071)]\n  - Yew now builds with `web-sys` by default. [[@jstarry], [#1092](https://github.com/yewstack/yew/pull/1092)]\n\n## ✨ yew-router **0.12.0** *(2020-04-25)*\n\n- ##### 🚨 Breaking changes\n  - Bump `yew` version to `0.15`.\n- #### Extraneous\n  - Remove `guide` example.\n\n## ✨ yew **0.14.3** *(2020-04-04)*\n\n- ##### 🛠 Fixes\n\n  - Remove `html!` component validation to allow generic components. [[@mankinskin], [#1065](https://github.com/yewstack/yew/pull/1065)]\n  - Improve `Debug` formatting for `VTag` and `VText`. [[@dancespiele], [#1059](https://github.com/yewstack/yew/pull/1059)]\n  - Implement `Default` for `Callback`. [[@TheNeikos], [#1043](https://github.com/yewstack/yew/pull/1043)]\n\n## ✨ yew **0.14.2** *(2020-03-23)*\n\n- ##### 🛠 Fixes\n\n  - Fix issue where components were rendered out of order. [[@mrh0057] & [@jstarry], [#1051](https://github.com/yewstack/yew/pull/1051)]\n  - Reset Select component correctly in Firefox / Edge. [[@kuy], [#987](https://github.com/yewstack/yew/pull/987)]\n\n## ✨ yew **0.14.1** *(2020-03-14)*\n\n- ##### 🛠 Fixes\n\n  - `Connected` message was only called for first bridge creation. [[@nicklaswj], [#1029](https://github.com/yewstack/yew/pull/1029)]\n\n## ✨ yew **0.14** *(2020-03-14)*\n\nHappy 🥧 (PI) Day! This release brings a number of bug fixes for `web-sys` apps and ergonomic improvements to the API. Huge thanks to the community for diving into the migration from `stdweb` to `web-sys` so quickly and uncovering these issues!\n\n\n- ##### ⚡️ Features\n\n  - Implemented `Clone` for `WebSocketStatus`. [[@kellytk], [#1023](https://github.com/yewstack/yew/pull/1023)]\n  - Improved ergonomics for message APIs by accepting `Into<Msg>`. [[@captain-yossarian], [#999](https://github.com/yewstack/yew/pull/999)]\n  - `html!` improved compiler messages and flexible syntax for `with props`. [[@captain-yossarian], [#960](https://github.com/yewstack/yew/pull/960)]\n\n- ##### 🛠 Fixes\n\n  - Fixed panic in `stdweb` `ResizeService` event handling. [[@nicklaswj], [#1014](https://github.com/yewstack/yew/pull/1014)]\n  - Removed build check for OS compatibility. [[@jstarry], [#1019](https://github.com/yewstack/yew/pull/1019)]\n  - Fixed interval and timer usage in `web-sys` workers by updating `gloo`. [[@jstarry], [#1018](https://github.com/yewstack/yew/pull/1018)]\n  - Send `Connected` message for Public agents. [[@TheNeikos], [#1007](https://github.com/yewstack/yew/pull/1007)]\n  - Fixed `web-sys` Public / Private agent initialization. [[@jstarry], [#1006](https://github.com/yewstack/yew/pull/1006)]\n  - Fixed websocket 'text' message handling for `web-sys` agents. [[@jstarry], [#1005](https://github.com/yewstack/yew/pull/1005)]\n\n- ##### 🚨 Breaking changes\n\n  - `FetchError::FetchFailed` enum variant now wraps a `String` to hold the failure reason. [[@jstarry], [#1025](https://github.com/yewstack/yew/pull/1025)]\n  - Message APIs now accept `Into<Msg>`, so calling `msg.into()` will cause compile errors. [[@captain-yossarian], [#999](https://github.com/yewstack/yew/pull/999)]\n\n## ✨ yew-router **0.11.0** *(2020-03-14)*\n\n- ##### 🛠 Fixes\n  - Fixed docs.rs document generation [[254](https://github.com/yewstack/yew_router/pull/254)] (Thanks @jetli)\n  - Fixed clippy for web_sys target [[249](https://github.com/yewstack/yew_router/pull/249)] (Thanks @jetli)\n\n## ✨ yew **0.13.2** *(2020-03-05)*\n\n- ##### 🛠 Fixes\n\n  - Fix clippy warning when building with `web_sys` feature. [[@jstarry], [#1001](https://github.com/yewstack/yew/pull/1001)]\n\n## ✨ yew **0.13.1** *(2020-03-04)*\n\n- ##### 🛠 Fixes\n\n  - Fix for `web-sys` version `0.3.36`. [[@detegr], [#997](https://github.com/yewstack/yew/pull/997)]\n\n## ✨ yew-router **0.10.0** *(2020-03-02)*\n\n- Bumped version of Yew from v0.12.0 to v0.13.0\n- This brings support for web_sys, which necessitates specifying either \"web_sys\" or \"std_web\" as a feature. (Thanks @tarkah)\n\n## ✨ yew **0.13** *(2020-03-01)*\n\n`web-sys` support has arrived! [@daxpedda] spear-headed the effort and courageously integrated `web-sys` while maintaining support for `stdweb` through no small amount of `cfg` macro usage. We chose to continue support for apps built with `stdweb` because the dev experience is still quite a bit better _(Unfortunately `cargo-web` is incompatible with `web-sys`)_. However, the Yew team recognizes that the future of `cargo-web` of `stdweb` are uncertain. For this reason, we recommend devs start making the switch over to `web-sys` and `wasm-bindgen`. We will likely invest in improving the dev experience with these tools so that switching over is eventually a no-brainer. Please reach out with ideas and feedback for this migration through Github issues and in our Gitter chatroom!\n\nAfter upgrading to v0.13, devs will now have to opt in to either `stdweb` or `web-sys` by using either the `\"web_sys\"` or `\"std_web\"` on the `yew` crate in their `Cargo.toml`.\n\n```toml\n# Choose `stdweb`\nyew = { version = \"0.13\", features = [\"std_web\"] }\n\n# Choose `web-sys`\nyew = { version = \"0.13\", features = [\"web_sys\"] }\n```\n\nLastly, take note that API docs on https://docs.rs/yew will be using the `\"web_sys\"` feature. For `\"std_web\"` docs, please visit https://docs.rs/yew-stdweb.\n\n\n- ##### ⚡️ Features\n\n  - Added support for building apps with `web-sys`. [[@daxpedda], [#961](https://github.com/yewstack/yew/pull/961)]\n  - Properties 2.0 [[@AlephAlpha], [#975](https://github.com/yewstack/yew/pull/975)]\n\n    Component properties are now assumed to be required unless otherwise annotated with a default value. Check out the proposal issue [#928](https://github.com/yewstack/yew/issues/928) for more details!\n\n- ##### 🛠 Fixes\n\n  - Fixed `Component` children re-rendering bug. [[@jstarry], [#980](https://github.com/yewstack/yew/pull/980)]\n  - Fixed panic when interacting with agents after receiving an agent message. [[@jstarry], [#981](https://github.com/yewstack/yew/pull/981)]\n  - Fixed panic when a component with a root `VRef` node is detached. [[@jstarry], [#983](https://github.com/yewstack/yew/pull/983)]\n  - Fixed annoying warning when a component with a root `VTag` node is detached. [[@jstarry], [#983](https://github.com/yewstack/yew/pull/983)]\n\n- ##### 🚨 Breaking changes\n\n  - Changed `Properties` macro behavior. Check out the proposal issue [#928](https://github.com/yewstack/yew/issues/928) for more details! [[@AlephAlpha], [#975](https://github.com/yewstack/yew/pull/975)]\n  - Cleaned up exported apis and doc visibility. [[@jstarry], [#977](https://github.com/yewstack/yew/pull/977)]\n  - `ReaderService` methods now return a `Result` instead of panicking.  [[@daxpedda], [#868](https://github.com/yewstack/yew/pull/868)]\n  - `FetchService` methods now return a `Result` instead of panicking.  [[@daxpedda], [#867](https://github.com/yewstack/yew/pull/867)]\n  - `StorageService` methods now return a `Result` instead of panicking.  [[@daxpedda], [#827](https://github.com/yewstack/yew/pull/827)]\n\n## ✨ yew-router **0.9.0** *(2020-02-25)*\n- ##### ⚡️ Features\n  - Improved error handling in macro. [[233](https://github.com/yewstack/yew_router/pull/233)] @jplatte\n- ##### 🛠 Fixes\n  - Fix RouterAnchor href [[228](https://github.com/yewstack/yew_router/pull/228)] @jetli\n  - Undo non-passive state for prevent_default [[240](https://github.com/yewstack/yew_router/pull/240)] @jetli\n\n## ✨ yew **0.12** *(2020-02-16)*\n\n- ##### ⚡️ Features\n\n  - Improved ergonomics for `html! { for .. }`. [[@jstarry], [#875](https://github.com/yewstack/yew/pull/875)]\n  - Added `#[props(default = \"fn_path\")]` for specifying a default property value. [[@AlephAlpha], [#881](https://github.com/yewstack/yew/pull/881)]\n  - Exposed the macros for creating format types. [[@ctm], [#883](https://github.com/yewstack/yew/pull/883)]\n  - Added support for binary-only and text-only formats in `WebSocketService`. [[@ctm], [#851](https://github.com/yewstack/yew/pull/851)]\n  - Implemented `PartialEq` for `ChildrenRenderer` to allow `children` comparison. [[@jstarry], [#916](https://github.com/yewstack/yew/pull/916)]\n  - Reduced restrictions on `ComponentLink` methods to improve `Future` support. [[@jplatte], [#931](https://github.com/yewstack/yew/pull/931)]\n  - Added `referrer`, `referrer_policy` and `integrity` to `FetchOptions`. [[@leo-lb], [#931](https://github.com/yewstack/yew/pull/931)]\n\n- ##### 🛠 Fixes\n\n  - Fixed touch event listeners. [[@AlephAlpha], [#872](https://github.com/yewstack/yew/pull/872)]\n  - Fixed bad behavior when setting a `ref` on a `Component`. [[@jstarry], [#913](https://github.com/yewstack/yew/pull/913)]\n  - Fixed ResizeTask cancellation. [[@jstarry], [#915](https://github.com/yewstack/yew/pull/915)]\n\n- ##### 🚨 Breaking changes\n\n  - Switched from using `failure` to `anyhow` and `thiserror` for Yew errors. [[@daxpedda], [#863](https://github.com/yewstack/yew/pull/863)]\n  - Removed `cancel` method from `Task` trait in favor of relying on [`Drop`](https://doc.rust-lang.org/book/ch15-03-drop.html). [[@kakoc], [#899](https://github.com/yewstack/yew/pull/899)]\n  - Renamed `NodeRef.try_into` to `NodeRef.cast` to avoid trait conflicts. [[@jstarry], [#917](https://github.com/yewstack/yew/pull/917)]\n\n## ✨ yew-router **0.8.1** *(2020-01-10)*\n\n- ##### 🛠 Fixes\n  - Fixed a dependency issue with `wasm-bindgen` that would cause builds to fail when building for the `wasm32-unknown-unknown` target.\n\n## ✨ yew-router **0.8.0** *(2020-01-09)*\n- ##### ⚡️ Features\n    - Use a default type parameter of `()` to specify state-related type parameters instead of the old macro-based solution. [[157](https://github.com/yewstack/yew_router/issues/157)]\n    - Remove need for `JsSerializable` bound on the state parameter used for storing extra data in the history API.[[185](https://github.com/yewstack/yew_router/issues/185)]\n    - RouterLink and RouterButton now support having children Html. This deprecates the `text` prop. [[192](https://github.com/yewstack/yew_router/issues/192)]\n    - Fragment routing is now easily implementable by using an adapter because parser rules for the routing syntax were relaxed. [[195](https://github.com/yewstack/yew_router/issues/195)] [[211](https://github.com/yewstack/yew_router/pull/211)]\n    - Support using this library only with the Switch derive, allowing it to run in non-web contexts. [[199](https://github.com/yewstack/yew_router/issues/199)]\n- ##### 🚨 Breaking changes\n  - If you were using `default-features = false`,  you will have to now specify `features = [\"service\"]` to get the same behavior as before. [[199](https://github.com/yewstack/yew_router/issues/199)]\n  - `RouterAnchor` and `RouterButton` now have props that take a `route: SW where SW: Switch` prop instead of a `link: String` and they now have a mandatory type parameter that specifies this `SW`. [[207](https://github.com/yewstack/yew_router/issues/207)]\n  - `Route`'s state field now holds a `T` instead of an `Option<T>`. [[205](https://github.com/yewstack/yew_router/issues/205)]\n  - Using default type parameters to specify the state typ instead of the macro that generated a module (`unit_state`) means that any imports from that module should now be replaced with the path that the type normally has in the project. [[157](https://github.com/yewstack/yew_router/issues/157)]\n- #### Inconsequential\n  - Change state related type parameters from `T` to `STATE`. [[208](https://github.com/yewstack/yew_router/issues/208)]\n\n## ✨ yew **0.11** *(2020-01-06)*\n\nThis release aims to lay the groundwork for Yew component libraries and clean up the API for the ever elusive 1.0 release.\n\n### Transition Guide\n\nThis release comes with a lot of breaking changes. We understand it's a hassle to update projects but the Yew team felt it was necessary to rip a few bandaids off now as we approach a 1.0 release in the (hopefully) near future. To ease the transition, here's a guide which outlines the main refactoring you will need to do for your project. (Note: all of the changes are reflected in the many example projects if you would like a proper reference example)\n\n#### 1. Callback syntax\n\nThis is the main painful breaking change. It applies to both element listeners as well as `Component` callback properties. A good rule of thumb is that your components will now have to retain a `ComponentLink` to create callbacks on demand or initialize callbacks in your component's `create()` method.\n\nBefore:\n```rust\nstruct MyComponent;\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => true,\n        }\n    }\n\n    fn view(&self) -> Html<Self> {\n        // BEFORE: Callbacks were created implicitly from this closure syntax\n        html! {\n            <button onclick=|_| Msg::Click>{ \"Click me!\" }</button>\n        }\n    }\n}\n```\n\nAfter:\n```rust\nstruct MyComponent {\n  link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => true,\n        }\n    }\n\n    fn view(&self) -> Html {\n        // AFTER: Callbacks need to be explicitly created now\n        let onclick = self.link.callback(|_| Msg::Click);\n        html! {\n            <button onclick=onclick>{ \"Click me!\" }</button>\n        }\n    }\n}\n```\n\nIf a closure has a parameter you will now need to specify the parameter's type.  A tip for finding the appropriate type is to search Yew's repo for the HTML attribute the closure is assigned to.\n\nFor example, `onkeydown` of `<button>`:\n\n```\nlet onkeydown = self.link.callback(|e: KeyDownEvent| {\n    // ...\n});\n```\n\nand\n\n```\nhtml! {\n    <button onkeydown=onkeydown type=\"button\">\n        { \"button\" }\n    </button>\n}\n```\n\n#### 2. Method Renames\n\nIt should be safe to do a project-wide find/replace for the following:\n\n- `send_self(` -> `send_message(`\n- `send_back(` -> `callback(`\n- `response(` -> `respond(`\n- `AgentUpdate` -> `AgentLifecycleEvent`\n\nThese renames will probably require some more care:\n\n- `fn handle(` -> `fn handle_input(` *(for Agent trait implementations)*\n\n#### 3. Drop Generic Types for `Html<Self>` -> `Html`\n\n:tada: We are pretty excited about this change! The generic type parameter\nwas confusing and restrictive and is now a thing of the past!\n\nBefore:\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html<Self> {\n        html! { /* ... */ }\n    }\n}\n```\n\nAfter:\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        html! { /* ... */ }\n    }\n}\n```\n\n#### 4. Properties must implement `Clone`\n\nIn yew v0.8 we removed the requirement that component properties implement `Clone`\nand in this release we are adding the requirement again. This change is needed\nto improve the ergonomics of nested components. The only time properties will be\ncloned is when a wrapper component re-renders nested children components.\n\n- ##### ⚡️ Features\n\n  - Added `html_nested!` macro to support nested iterable children access. [[@trivigy], [#843](https://github.com/yewstack/yew/pull/843)]\n  - Added `bincode` to the list of supported formats. [[@serzhiio], [#806](https://github.com/yewstack/yew/pull/806)]\n  - Added a `noop()` convenience method to `Callback` which creates a no-op callback. [[@mdtusz], [#793](https://github.com/yewstack/yew/pull/793)]\n  - The `html!` macro now accepts a `Callback` for element listeners. [[@jstarry], [#777](https://github.com/yewstack/yew/pull/777)]\n\n  ```rust\n  struct MyComponent {\n      onclick: Callback<ClickEvent>,\n  }\n\n  enum Msg {\n      Click,\n  }\n\n  impl Component for MyComponent {\n      type Message = Msg;\n      type Properties = ();\n\n      fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n          MyComponent {\n              onclick: link.callback(|_| Msg::Click),\n          }\n      }\n\n      fn update(&mut self, msg: Self::Message) -> ShouldRender {\n          match msg {\n              Msg::Click => true,\n          }\n      }\n\n      fn view(&self) -> Html {\n          html! {\n              <button onclick=&self.onclick>{ \"Click me!\" }</button>\n          }\n      }\n  }\n  ```\n\n  - Add `send_message_batch` method to `ComponentLink`. [[@hgzimmerman], [#748](https://github.com/yewstack/yew/pull/748)]\n  - Allow compilation to `wasi` target without `wasm_bindgen`. [[@dunnock], [#746](https://github.com/yewstack/yew/pull/746)]\n  - `AgentLink` now implements `Clone` which enables `Future` usage without explicit Yew framework support. [[@izissise], [#802](https://github.com/yewstack/yew/pull/802)]\n  - `ComponentLink` now implements `Clone` which enables `Future` usage without explicit Yew framework support. [[@hgzimmerman], [#749](https://github.com/yewstack/yew/pull/749)]\n\n  ```rust\n  use wasm_bindgen::JsValue;\n  use wasm_bindgen_futures::future_to_promise;\n\n  // future must implement `Future<Output = Component::Message> + 'static`\n  let link = self.link.clone();\n  let js_future = async move {\n      link.send_message(future.await);\n      Ok(JsValue::NULL)\n  };\n\n  future_to_promise(js_future);\n  ```\n\n- ##### 🛠 Fixes\n\n  - Fixed handling of boolean tag attributes. [[@mrh0057], [#840](https://github.com/yewstack/yew/pull/840)]\n  - Improved nested component ergonomics. [[@jstarry], [#780](https://github.com/yewstack/yew/pull/780)]\n\n  ```rust\n  fn view(&self) -> Html {\n      html! {\n          <Wrapper>\n              // This is now valid. (before #780, this would cause a lifetime\n              // compile error because children nodes were moved into a closure)\n              <Nested on_click=&self.nested_on_click />\n          </Wrapper>\n      }\n  }\n  ```\n\n  - Creating a `Callback` with `ComponentLink` is no longer restricted to mutable references, improving ergonomics. [[@jstarry], [#780](https://github.com/yewstack/yew/pull/780)]\n  - The `Callback` `reform` method no longer consumes self making it easier to \"reverse map\" a `Callback`. [[@jstarry], [#779](https://github.com/yewstack/yew/pull/779)]\n\n  ```rust\n  pub struct ListHeader {\n      props: Props,\n  }\n\n  #[derive(Properties, Clone)]\n  pub struct Props {\n      #[props(required)]\n      pub on_hover: Callback<Hovered>,\n      #[props(required)]\n      pub text: String,\n  }\n\n  impl Component for ListHeader {\n      type Message = ();\n      type Properties = Props;\n\n      fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {\n          ListHeader { props }\n      }\n\n      fn update(&mut self, _: Self::Message) -> ShouldRender {\n          false\n      }\n\n      fn view(&self) -> Html {\n          let onmouseover = self.props.on_hover.reform(|_| Hovered::Header);\n          html! {\n              <div class=\"list-header\" onmouseover=onmouseover>\n                  { &self.props.text }\n              </div>\n          }\n      }\n  }\n  ```\n\n  - Reduced allocations in the `Classes` `to_string` method. [[@hgzimmerman], [#772](https://github.com/yewstack/yew/pull/772)]\n  - Empty string class names are now filtered out to prevent panics. [[@jstarry], [#770](https://github.com/yewstack/yew/pull/770)]\n\n- ##### 🚨 Breaking changes\n\n  - Components with generic args now need to be closed with the full type path. (e.g. `html! { <Wrapper<String>></Wrapper<String>>}`) [[@jstarry], [#837](https://github.com/yewstack/yew/pull/837)]\n  - Changed `VTag` listener type from `Box<dyn Listener>` to `Rc<dyn Listener>`. [[@jstarry], [#786](https://github.com/yewstack/yew/pull/786)]\n  - `Properties` need to implement `Clone` again in order to improve nested component ergonomics. [[@jstarry], [#786](https://github.com/yewstack/yew/pull/786)]\n  - Removed `send_future` method from `ComponentLink` since it is no longer necessary for using Futures with Yew. [[@hgzimmerman], [#799](https://github.com/yewstack/yew/pull/799)]\n  - Removed generic type parameter from `Html` and all virtual node types: `VNode`, `VComp`, `VTag`, `VList`, `VText`, etc. [[@jstarry], [#783](https://github.com/yewstack/yew/pull/783)]\n  - Removed support for macro magic closure syntax for element listeners. (See transition guide for how to pass a `Callback` explicitly instead). [[@jstarry], [#782](https://github.com/yewstack/yew/pull/782)]\n  - Renamed `Agent` methods and event type for clarity. `handle` -> `handle_input`, `AgentUpdate` -> `AgentLifecycleEvent`, `response` -> `respond`. [[@philip-peterson], [#751](https://github.com/yewstack/yew/pull/751)]\n  - The `ComponentLink` `send_back` method has been renamed to `callback` for clarity. [[@jstarry], [#780](https://github.com/yewstack/yew/pull/780)]\n  - The `ComponentLink` `send_self` and `send_self_batch` methods have been renamed to `send_message` and `send_message_batch` for clarity. [[@jstarry], [#780](https://github.com/yewstack/yew/pull/780)]\n  - The `Agent` `send_back` method has been renamed to `callback` for clarity. [[@jstarry], [#780](https://github.com/yewstack/yew/pull/780)]\n  - The `VTag` `children` value type has changed from `Vec<VNode>` to `VList`. [[@jstarry], [#754](https://github.com/yewstack/yew/pull/754)]\n\n\n## ✨ yew **0.10** *(2019-11-11)*\n\n- ##### ⚡️ Features\n\n  - `Future` support :tada: A `Component` can update following the completion of a `Future`. Check out [this example](https://github.com/yewstack/yew/tree/v0.14.0/examples/futures) to see how it works. This approach was borrowed from a fork of Yew called [`plaster`](https://github.com/carlosdp/plaster) created by [@carlosdp]. [[@hgzimmerman], [#717](https://github.com/yewstack/yew/pull/717)]\n  - Added the `agent` and `services` features so that this functionality can be disabled (useful if you are switching to using `Future`s). [[@hgzimmerman], [#684](https://github.com/yewstack/yew/pull/684)]\n  - Add `ref` keyword for allowing a `Component` to have a direct reference to its rendered elements. For example, you can now easily focus an `<input>` element after mounting. [[@jstarry], [#715](https://github.com/yewstack/yew/pull/715)]\n\n  ```rust\n  use stdweb::web::html_element::InputElement;\n  use stdweb::web::IHtmlElement;\n  use yew::prelude::*;\n\n  pub struct Input {\n      node_ref: NodeRef,\n  }\n\n  impl Component for Input {\n      type Message = ();\n      type Properties = ();\n\n      fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n          Input {\n              node_ref: NodeRef::default(),\n          }\n      }\n\n      fn mounted(&mut self) -> ShouldRender {\n          if let Some(input) = self.node_ref.try_into::<InputElement>() {\n              input.focus();\n          }\n          false\n      }\n\n      fn update(&mut self, _: Self::Message) -> ShouldRender {\n          false\n      }\n\n      fn view(&self) -> Html<Self> {\n          html! {\n              <input ref=self.node_ref.clone() type=\"text\" />\n          }\n      }\n  }\n  ```\n\n  - Make `Agent` related types `public` to allow other crates to create custom agents. [[@dunnock], [#721](https://github.com/yewstack/yew/pull/721)]\n  - `Component::change` will now return `false` for components that have `Component::Properties == ()`. [[@kellytk], [#690](https://github.com/yewstack/yew/pull/690)]]\n  - Updated `wasm-bindgen` dependency to `0.2.54`. Please update your `wasm-bindgen-cli` tool by running `cargo install --force --version 0.2.54 -- wasm-bindgen-cli`. [[@jstarry], [#730](https://github.com/yewstack/yew/pull/730)], [[@ctaggart], [#681](https://github.com/yewstack/yew/pull/681)]\n\n- ##### 🛠 Fixes\n\n  - Fixed the mount order of components. The root component will be mounted after all descendants have been mounted. [[@jstarry], [#725](https://github.com/yewstack/yew/pull/725)]\n  - All public items now implement `Debug`. [[@hgzimmerman], [#673](https://github.com/yewstack/yew/pull/673)]\n\n- ##### 🚨 Breaking changes\n\n  - Minimum rustc version has been bumped to `1.39.0` for `Future` support. [[@jstarry], [#730](https://github.com/yewstack/yew/pull/730)]\n  - `Component` now has a required `view` method and automatically implements the `Renderable` trait. The `view` method in the `Renderable` trait has been renamed to `render`. [[@jstarry], [#563](https://github.com/yewstack/yew/pull/563)]\n\n    Before:\n    ```rust\n    impl Component for MyComponent {\n        type Message = Msg;\n        type Properties = ();\n\n        fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n            MyComponent {}\n        }\n\n        fn update(&mut self, msg: Self::Message) -> ShouldRender {\n            true\n        }\n    }\n\n    impl Renderable<MyComponent> for MyComponent {\n        fn view(&self) -> Html<Self> {\n            html! { \"hello\" }\n        }\n    }\n    ```\n\n    After:\n    ```rust\n    impl Component for MyComponent {\n        type Message = Msg;\n        type Properties = ();\n\n        fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n            MyComponent {}\n        }\n\n        fn update(&mut self, msg: Self::Message) -> ShouldRender {\n            true\n        }\n\n        fn view(&self) -> Html<Self> {\n            html! { \"hello\" }\n        }\n    }\n    ```\n\n  - Removed the `Transferable` trait since it did no more than extend the serde `Serialize` and `Deserialize` traits. [[@hgzimmerman], [#319](https://github.com/yewstack/yew/pull/319)]\n\n    Before:\n    ```rust\n    impl Transferable for Input {}\n    #[derive(Serialize, Deserialize)]\n    pub enum Input {\n      Connect,\n    }\n    ```\n\n    After:\n    ```rust\n    #[derive(Serialize, Deserialize)]\n    pub enum Input {\n      Connect,\n    }\n    ```\n  - `WebSocketService::connect` will now return a `Result` in order to stop panicking on malformed urls. [[@lizhaoxian], [#727](https://github.com/yewstack/yew/pull/727)]\n  - `VTag` now is boxed within `VNode` to shrink the size of its enum representation. [[@hgzimmerman], [#675](https://github.com/yewstack/yew/pull/675)]\n\n## ✨ yew-router **0.7.0** *(2019-11-11)*\n\n- ##### ⚡️ Features\n  - Redirects that happen in the `Router` component actually change the url in the browser [[171](https://github.com/yewstack/yew_router/issues/171)]\n  - Allow parsing (almost) any character after a `#` is encountered in matcher strings. \n  This enables this library to be used as a fragment router. [[150](https://github.com/yewstack/yew_router/issues/150)]\n- ##### 🛠 Fixes\n  - Allow `!` to appear after `{...}` in matcher strings. [[148](https://github.com/yewstack/yew_router/issues/148)]\n  - Matcher strings can now start with `&`. [[168](https://github.com/yewstack/yew_router/issues/168)] \n- ##### 🚨 Breaking changes\n  - Upgrade to Yew 0.10.0\n  - Switch components now need to implement `Clone` in order to be used with the `Router` [[171](https://github.com/yewstack/yew_router/issues/171)]\n\n## ✨ yew-router **0.6.1** *(2019-11-01)*\n- ##### ⚡️ Features\n  - Bring back `{}`, `{*}`, and `{<number>}` capture syntax for tuple structs/enum variants. \n  If your variant or struct doesn't have named fields, you don't need to supply names in the matcher string [[116](https://github.com/yewstack/yew_router/issues/116)]\n  - Allow ! special character in more places.\n  - Greatly improve the quality of matcher string parsing errors. [[171](https://github.com/yewstack/yew_router/issues/149)]\n  - Add `impl<SW: Switch, T> From<SW> for Route<T>`. Now Routes can be created from Switches easily.\n  - Allow escaping {, }, and ! special characters by using `{{`, `}}`, and `!!` respectively.\n  - Provide a correct error message when attempting to derive `Switch` for a Unit struct/variant with a capture group.\n\n## ✨ yew-router **0.6.0** *(2019-10-24)*\n- ##### ⚡️ Features\n  - `Switch` trait and Proc Macro enables extracting data from route strings.\n  - `Router` component added.\n  - `RouterLink` and `RouterButton` helper components added.\n- ##### 🚨 Breaking changes\n  - Nearly everything. Most items were renamed.\n  - Upgrade to Yew 0.9.0\n\n## ✨ yew **0.9.2** *(2019-10-12)*\n\n- ##### 🛠 Fixes\n\n  - Fix `yew-macro` dependency version\n\n## ✨ yew **0.9.1** *(2019-10-12)*\n\nHappy Canadian Thanksgiving! 🦃\n\n- ##### ⚡️ Features\n\n  - Implemented `Default` trait for `VNode` so that `unwrap_or_default` can be called on `Option<Html<Self>>`. [[@hgzimmerman], [#672](https://github.com/yewstack/yew/pull/672)]\n  - Implemented `PartialEq` trait for `Classes` so that is more ergonomic to use `Classes` type in component props. [[@hgzimmerman], [#680](https://github.com/yewstack/yew/pull/680)]\n  - Updated `wasm-bindgen` dependency to `0.2.50`. Please update your `wasm-bindgen-cli` tool by running `cargo install --force --version 0.2.50 -- wasm-bindgen-cli`. [[@jstarry], [#695](https://github.com/yewstack/yew/pull/695)]\n\n- ##### 🛠 Fixes\n\n  - Fixed issue where text nodes were sometimes rendered out of order. [[@jstarry], [#697](https://github.com/yewstack/yew/pull/697)]\n  - Fixed regression introduced in 0.9.0 that prevented tag attributes from updating properly. [[@jstarry], [#698](https://github.com/yewstack/yew/pull/698)]\n  - Fixed emscripten builds by pinning the version for the `ryu` downstream dependency. [[@jstarry], [#703](https://github.com/yewstack/yew/pull/703)]\n  - Updated `stdweb` to `0.4.20` which fixed emscripten builds and unblocked updating `wasm-bindgen` to `0.2.50`. [[@ctaggart], [@jstarry], [#683](https://github.com/yewstack/yew/pull/683), [#694](https://github.com/yewstack/yew/pull/694)]\n  - Cleaned up build warnings for missing `dyn` keywords. [[@benreyn], [#687](https://github.com/yewstack/yew/pull/687)]\n\n## ✨ yew **0.9** *(2019-09-27)*\n\n- ##### ⚡️ Features\n\n  - New `KeyboardService` for setting up key listeners on browsers which support the feature. [[@hgzimmerman], [#647](https://github.com/yewstack/yew/pull/647)]\n  - `ComponentLink` can now create a `Callback` with more than one `Message`. The `Message`'s will be batched together so that the `Component` will not be re-rendered more than necessary. [[@stkevintan], [#660](https://github.com/yewstack/yew/pull/660)]\n  - `Message`'s to `Public` `Agent`'s will now be queued if the `Agent` hasn't finished setting up yet. [[@serzhiio], [#596](https://github.com/yewstack/yew/pull/596)]\n  - `Agent`'s can now be connected to without a `Callback`. Instead of creating a bridge to the agent, create a dispatcher like so: `MyAgent::dispatcher()`. [[@hgzimmerman], [#639](https://github.com/yewstack/yew/pull/639)]\n  - `Component`'s can now accept children in the `html!` macro. [[@jstarry], [#589](https://github.com/yewstack/yew/pull/589)]\n\n    ```rust\n    // app.rs\n\n    html! {\n      <MyList name=\"Grocery List\">\n        <MyListItem text=\"Apples\" />\n      </MyList>\n    }\n    ```\n\n    ```rust\n    // my_list.rs\n\n    use yew::prelude::*;\n\n    pub struct MyList(Props);\n\n    #[derive(Properties)]\n    pub struct Props {\n        #[props(required)]\n        pub name: String,\n        pub children: Children<MyListItem>,\n    }\n\n    impl Renderable<MyList> for MyList {\n      fn view(&self) -> Html<Self> {\n        html! {{\n          self.props.children.iter().collect::<Html<Self>>()\n        }}\n      }\n    }\n    ```\n\n  - `Iterator`s can now be rendered in the `html!` macro without using the `for` keyword. [[@hgzimmerman], [#622](https://github.com/yewstack/yew/pull/622)]\n\n    Before:\n    ```rust\n    html! {{\n      for self.props.items.iter().map(renderItem)\n    }}\n    ```\n\n    After:\n    ```rust\n    html! {{\n      self.props.items.iter().map(renderItem).collect::<Html<Self>>()\n    }}\n    ```\n\n  - Closures are now able to be transformed into optional `Callback` properties. [[@Wodann], [#612](https://github.com/yewstack/yew/pull/612)]\n  - Improved CSS class ergonomics with new `Classes` type. [[@DenisKolodin], [#585](https://github.com/yewstack/yew/pull/585)], [[@hgzimmerman], [#626](https://github.com/yewstack/yew/pull/626)]\n  - Touch events are now supported `<div ontouchstart=|_| Msg::TouchStart>` [[@boydjohnson], [#584](https://github.com/yewstack/yew/pull/584)], [[@jstarry], [#656](https://github.com/yewstack/yew/pull/656)]\n  - The `Component` trait now has an `mounted` method which can be implemented to react to when your components have been mounted to the DOM. [[@hgzimmerman], [#583](https://github.com/yewstack/yew/pull/583)]\n  - Additional Fetch options `mode`, `cache`, and `redirect` are now supported [[@davidkna], [#579](https://github.com/yewstack/yew/pull/579)]\n  - The derive props macro now supports Properties with lifetimes [[@jstarry], [#580](https://github.com/yewstack/yew/pull/580)]\n  - New `ResizeService` for registering for `window` size updates [[@hgzimmerman], [#577](https://github.com/yewstack/yew/pull/577)]\n\n- ##### 🛠 Fixes\n\n  - Fixed JS typo in RenderService. This was causing animation frames to not be dropped correctly. [[@jstarry], [#658](https://github.com/yewstack/yew/pull/658)]\n  - Fixed `VNode` orphaning bug when destroying `VTag` elements. This caused some `Component`s to not be properly destroyed when they should have been. [[@hgzimmerman], [#651](https://github.com/yewstack/yew/pull/651)]\n  - Fix mishandling of Properties `where` clause in derive_props macro [[@astraw], [#640](https://github.com/yewstack/yew/pull/640)]\n\n- ##### 🚨 Breaking changes\n\n  None\n\n## ✨ yew **0.8** *(2019-08-10)*\n\n***Props! Props! Props!***\n\nThis release introduces a more developer friendly way to handle your `Component` props. Use the new `#[derive(Properties)]` macro to beef up your props! Property values can now be annotated as `#[props(required)]` which will enforce that props are present at compile time. This means that your props struct no longer needs to implement `Default`, so time to clean up all of those prop values you wrapped in `Option` to have a default value.\n\n- ##### ⚡️ Features\n\n  - `html!` - Self-closing html tags can now be used: `<div class=\"marker\" />` [[@totorigolo], [#523](https://github.com/yewstack/yew/pull/523)]\n  - `html!` - SVG name-spaced tags are now supported! [[@jstarry], [#550](https://github.com/yewstack/yew/pull/550)]\n  - Properties can now be required at compile time [[@jstarry], [#553](https://github.com/yewstack/yew/pull/525)]\n  - App components can now be mounted with properties [[@jstarry], [#567](https://github.com/yewstack/yew/pull/567)]\n  - Apps can now be mounted as the `<body>` tag [[@jstarry], [@kellytk], [#540](https://github.com/yewstack/yew/pull/540)]\n  - Content editable elements can now trigger `oninput` events [[@tiziano88], [#549](https://github.com/yewstack/yew/pull/549)]\n\n- ##### 🛠 Fixes\n\n  - `html!` - Class name order is now preserved which unlocks the use of Semantic UI [[@charvp], [#424](https://github.com/yewstack/yew/pull/424)]\n  - `html!` - Dashed tag names and properties are supported [[@jstarry], [#512](https://github.com/yewstack/yew/pull/512), [#550](https://github.com/yewstack/yew/pull/550)]\n  - `html!` - All rust keywords can be used as tag attributes [[@jstarry], [#550](https://github.com/yewstack/yew/pull/550)]\n  - `html!` - Support `Callback` closure with explicit return type [[@totorigolo], [#564](https://github.com/yewstack/yew/pull/564)]\n  - `html!` - Fixed edge case where `>` token would break parser [[@totorigolo], [#565](https://github.com/yewstack/yew/pull/565)]\n  - Performance improvement to the diff engine [[@totorigolo], [#539](https://github.com/yewstack/yew/pull/539)]\n  - `Properties` no longer need to implement the `PartialEq`, `Clone`, or `Default` traits [[@jstarry], [#553](https://github.com/yewstack/yew/pull/553)]\n  - `Component` will not panic if the `change` method is unimplemented [[@jstarry], [#554](https://github.com/yewstack/yew/pull/554)]\n\n- ##### 🚨 Breaking changes\n\n  - The `Component::Properties` associated type must implement the new `Properties` trait [[@jstarry], [#553](https://github.com/yewstack/yew/pull/553)]\n\n    The new `Properties` trait is what powers the ability to check required props are present at compile time. Use the derive props macro to implement automatically.\n\n    ```rust\n    use yew::Properties;\n\n    #[derive(Properties)]\n    pub struct Props {\n      #[props(required)]\n      pub value: MyStruct,\n    }\n    ```\n\n  - `Callback` props no longer transform into `Option` types [[@jstarry], [#553](https://github.com/yewstack/yew/pull/553)]\n\n    ```rust\n    html! { <Button on_click=Msg::Click /> }\n    ```\n\n    ***before:***\n\n    ```rust\n    #[derive(PartialEq, Clone, Default)]\n    pub struct Props {\n        on_click: Option<Callback<()>>,\n    }\n    ```\n\n    ***after:*** *note the `#[props(required)]` attribute*\n\n    ```rust\n    #[derive(PartialEq, Properties)]\n    pub struct Props {\n        #[props(required)]\n        on_click: Callback<()>,\n    }\n    ```\n\n## ✨ yew **0.7** *(2019-07-19)*\n\n***Commas? We don't need no stinkin' commas!***\n\nThis release brings a new and improved `html!` macro for writing JSX-like syntax. Commas and colons are no longer necessary now that the macro is written as a procedural macro.\n\n- ##### ⚡️ Features\n  - `html!{}` is now valid syntax and can be used to render nothing [[@jstarry], [#500](https://github.com/yewstack/yew/pull/500)]\n  - Apps can now be built without `cargo-web` using `wasm-bindgen` [[@jstarry], [#497](https://github.com/yewstack/yew/pull/497)]\n  - `Callback` now implements `Debug` [[@DenisKolodin], [#485](https://github.com/yewstack/yew/pull/485)]\n  - New utility method for getting the `host` of the current page [[@DenisKolodin], [#509](https://github.com/yewstack/yew/pull/509)]\n\n- ##### 🛠 Fixes\n  - `html!` - Commas are no longer necessary for splitting up attributes [[@jstarry], [#500](https://github.com/yewstack/yew/pull/500)]\n  - `html!` - Colons are no longer necessary for denoting a `Component` tag [[@jstarry], [#500](https://github.com/yewstack/yew/pull/500)]\n  - Textarea value can be now be set: `<textarea value=\"content\">` [[@DenisKolodin], [#476](https://github.com/yewstack/yew/pull/476)]\n  -  changed `StorageService::restore` to take an immutable receiver [[@dermetfan], [#480](https://github.com/yewstack/yew/pull/480)]\n  - Fixed a component rendering bug [[@jstarry], [#502](https://github.com/yewstack/yew/pull/502)]\n\n## ✨ yew **0.6** *(2019-02-20)*\n\n- ##### ⚡️ Features\n  - Added `start_app` convenience method for initializing the app and mounting it to the body [[@DenisKolodin], [#462](https://github.com/yewstack/yew/pull/462)]\n  - Added handling of files of `input` element. There is now a `ChangeData::Files` variant for the `onchange` handler [[@DenisKolodin], [#464](https://github.com/yewstack/yew/pull/464)]\n  - Added `ReaderService` to read data from `File` instances. [[@DenisKolodin], [#464](https://github.com/yewstack/yew/pull/464), [#468](https://github.com/yewstack/yew/pull/468)]\n\n- ##### 🛠 Fixes\n  - It was impossible to set `value` attribute for any tag instead of `option`, because it used\n  inner value of `VTag` to keep the value for `input` element. Now `value` attribute works\n  for `options`, `progress` tags, etc.\n\n\n- #### 🔮 Examples\n  - New example `file_upload` that prints sizes of uploaded files [[@DenisKolodin], [#464](https://github.com/yewstack/yew/pull/464)]\n\n## ✨ yew **0.5** *(2019-02-01)*\n\n**🎶 Secret Agent Man 🎶**\n\nThis release introduces the concept of an `Agent`. Agents are separate activities which you could run in the same thread or in a separate thread. There are three types of agents `Context`, `Job`, `Public` described below. To connect to an agent use the `Worker::bridge` method and pass a link of component's environment to it.\n\n- ##### ⚡️ Features\n  - Introduced the concept of an `Agent` which can run processes in other contexts:\n    - `Context` agent spawns once per thread\n    - `Job` agent spawns for every bridge\n    - `Public` agent spawns an agent in a separate thread (it uses [Web Workers API] under the hood).\n  - Allow setting the whole properties struct of a component with `<Component: with props />`\n  - `ComponentLink` now has a `send_self` method which allows components to update themselves [[@DenisKolodin], [#365](https://github.com/yewstack/yew/pull/365)]\n  - All services are re-exported within the `yew::services` module.\n  - `html!` macro supports multiple classes in a single string:\n  `<a class=\"button is-primary\",>`.\n  - Added `FetchOptions` to allow setting `Credentials` of `fetch` request.\n  - `FetchService` aborts requests using `AbortController`.\n  - Added `SubmitEvent` with `onsubmit` rule.\n\n\n- ##### 🛠 Fixes\n\n  - Bug with emscripten target `RuntimeError: index out of bounds` fixed with a new scheduler [[@DenisKolodin], [#272](https://github.com/yewstack/yew/pull/272)]\n\n- ##### 🚨 Breaking changes\n  - `send_back` method requires a mutable reference to `self`. This was added to prevent creating callbacks in `view` implementations. [[@DenisKolodin], [#367](https://github.com/yewstack/yew/pull/367)]\n  - `Context` requirement removed. It's no longer necessary to use `Component<CTX>` type parameter. Instead, a link to the environment is provided with the `Component::create` call. [[@DenisKolodin], [#272](https://github.com/yewstack/yew/pull/272)]\n\n## ✨ yew **0.4** *(2018-06-01)*\n## ✨ yew **0.3** *(2018-04-23)*\n## ✨ yew **0.2** *(2018-01-08)*\n## ✨ yew **0.1** *(2017-12-31)*\n\n[Web Workers API]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API\n[@alexschrod]: https://github.com/alexschrod\n[@AlephAlpha]: https://github.com/AlephAlpha\n[@astraw]: https://github.com/astraw\n[@bakape]: https://github.com/bakape\n[@bryanjswift]: https://github.com/bryanjswift\n[@boydjohnson]: https://github.com/boydjohnson\n[@captain-yossarian]: https://github.com/captain-yossarian\n[@carlosdp]: https://github.com/carlosdp\n[@charvp]: https://github.com/charvp\n[@ctaggart]: https://github.com/ctaggart\n[@ctm]: https://github.com/ctm\n[@ctron]: https://github.com/ctron\n[@domdir]: https://github.com/domdir\n[@D4nte]: https://github.com/D4nte\n[@dancespiele]: https://github.com/dancespiele\n[@daxpedda]: https://github.com/daxpedda\n[@davidkna]: https://github.com/davidkna\n[@DenisKolodin]: https://github.com/DenisKolodin\n[@dermetfan]: https://github.com/dermetfan\n[@detegr]: https://github.com/Detegr\n[@dunnock]: https://github.com/dunnock\n[@faulesocke]: https://github.com/faulesocke\n[@hgzimmerman]: https://github.com/hgzimmerman\n[@izissise]: https://github.com/izissise\n[@joaquindk]: https://github.com/joaquindk\n[@jplatte]: https://github.com/jplatte\n[@jstarry]: https://github.com/jstarry\n[@kakoc]: https://github.com/kakoc\n[@kaoet]: https://github.com/kaoet\n[@kellytk]: https://github.com/kellytk\n[@kuy]: https://github.com/kuy\n[@leo-lb]: https://github.com/leo-lb\n[@liquidblock]: https://github.com/liquidblock\n[@lizhaoxian]: https://github.com/lizhaoxian\n[@lukerandall]: https://github.com/lukerandall\n[@mankinskin]: https://github.com/mankinskin\n[@mdtusz]: https://github.com/mdtusz\n[@mkawalec]: https://github.com/mkawalec\n[@mrh0057]: https://github.com/mrh0057\n[@nicklaswj]: https://github.com/nicklaswj\n[@philip-peterson]: https://github.com/philip-peterson\n[@serzhiio]: https://github.com/serzhiio\n[@siku2]: https://github.com/siku2\n[@Stigjb]: https://github.com/Stigjb\n[@stkevintan]: https://github.com/stkevintan\n[@TheNeikos]: https://github.com/TheNeikos\n[@teymour-aldridge]: https://github.com/teymour-aldridge\n[@tiziano88]: https://github.com/tiziano88\n[@trivigy]: https://github.com/trivigy\n[@totorigolo]: https://github.com/totorigolo\n[@Wodann]: https://github.com/Wodann\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n* Accepting and using the preferred gender pronouns of all people who have specified them involved in the project.\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement by emailing\n`maintainers@yew.rs`.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guide\n\n## Setting up your local development environment\n\n### Add the Wasm target\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### Install [cargo-make](https://github.com/sagiegurari/cargo-make)\n\n```bash\ncargo install cargo-make\n```\n\nYou can use the following command to list all available tasks for Yew:\n\n```bash\ncargo make --list-all-steps\n```\n\nThe most important tasks are outlined below.\n\n## Tests\n\nTo run all tests, use the following command:\n\n```bash\ncargo make test-flow\n```\n\n### Browser tests\n\n`cargo make test` will automatically download Geckodriver to a temporary location if it isn't in the PATH.\n\nBecause Geckodriver looks for `firefox` in the path, if you use\nFireFox Developer Edition, you may get an error, because Developer Editions\nbinary is called `firefox-developer-edition`.\nTo fix this, either install the standard version of Firefox or symlink\n`firefox` to `firefox-developer-edition`.\n\n### Fetch service tests\n\nThe tests for the fetch service require a local [httpbin](https://httpbin.org/) server.\nIf you have [Docker](https://www.docker.com/) installed,\n`cargo make test` will automatically run httpbin in a container for you.\n\nAlternatively, you can set the `HTTPBIN_URL` environment variable to the URL you wish to run tests against.\n\n### Macro tests\n\nWhen adding or updating tests, please make sure to update the appropriate `stderr` file, which you can find [here](https://github.com/yewstack/yew/tree/master/packages/yew-macro/tests/macro) for the `html!` macro.\nThese files ensure that macro compilation errors are correct and easy to understand.\nThese errors can change with each release of the compiler, so they should be generated with the Rust version 1.56\n(because some tests make use of const generics which were stabilized in that version).\n\nTo update or generate a new `stderr` file you can run `cargo make test-overwrite` in the `yew-macro` directory.\n\n## Spell Checking\n\nWe use [typos](https://github.com/crate-ci/typos) to catch spelling mistakes. CI runs it automatically on every PR.\n\nTo run it locally:\n\n```bash\ncargo install typos-cli --locked\ntypos        # check for typos\ntypos -w     # auto-fix typos\n```\n\nFalse positives can be configured in `_typos.toml` at the repo root.\n\n## Linting\n\nThe following command checks the code using Rustfmt and Clippy:\n\n```bash\ncargo make lint\n```\n\nTo automatically fix formatting issues, run `cargo +nightly fmt` first.\n\n## Benchmarks\n\njs-framework-benchmark is used as a benchmark for the framework as a whole.\nSimply clone [bakape/js-framework-benchmark](https://github.com/bakape/js-framework-benchmark)\nand follow the repository's README.\n\n## Writing APIs\n\nWhen 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?\n\nBelow, 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.\n\n- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines/)\n- [Elegant Library APIs in Rust](https://deterministic.space/elegant-apis-in-rust.html)\n\n## Website\n\nThe source code of our website ([https://yew.rs](https://yew.rs)) is in the [website directory](website).\nMost of the times, edits can be done in markdown.\n\n[website/README.md](website/README.md) has more detailed instructions.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"packages/*\",\n    \"tools/*\",\n    \"examples/*\",\n]\nexclude = [\"examples/.cargo\"]\ndefault-members = [\n    \"packages/*\",\n]\nresolver = \"3\"\n\n[profile.release]\nlto = true\ncodegen-units = 1\npanic = \"abort\"\nopt-level = \"z\"\n\n[profile.bench]\nlto = true\ncodegen-units = 1\nopt-level = 3\n\n[workspace.lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = [\n    \"cfg(documenting)\",\n    \"cfg(verbose_tests)\",\n    \"cfg(yew_lints)\",\n    \"cfg(nightly_yew)\",\n    \"cfg(wasm_bindgen_unstable_test_coverage)\"\n]}\n[workspace.dependencies]\ntokio = { version = \"1.50.0\" }\nimplicit-clone = { version = \"0.6.0\" }\nproc-macro2 = \"1\"\nquote = \"1\"\nsyn = { version = \"2\" }\ntrybuild = \"1\"\nclap = { version = \"4\", features = [\"derive\"] }\nwasm-bindgen = \"0.2\"\nwasm-bindgen-futures = \"0.4\"\nwasm-bindgen-test = \"0.3\"\njs-sys = \"0.3\"\nweb-sys = \"0.3\"\ngloo = \"0.11\"\nserde = \"1\"\nserde_json = \"1\"\nfutures = { version = \"0.3\", default-features = false }\nlog = \"0.4\"\nwasm-logger = \"0.2\"\nrand = \"0.9\"\ngetrandom = { version = \"0.3\", features = [\"wasm_js\"] }\ninstant = { version = \"0.1\", features = [\"wasm-bindgen\"] }\nrustversion = \"1\"\nstrum = \"0.28\"\nstrum_macros = \"0.28\"\nanyhow = \"1\"\nchrono = \"0.4\"\nthiserror = \"2.0\"\nbincode = { version = \"2.0.0-rc.3\", features = [\"serde\"] }\nreqwest = \"0.13\"\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "                              Apache License\n                        Version 2.0, January 2004\n                     http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n   \"License\" shall mean the terms and conditions for use, reproduction,\n   and distribution as defined by Sections 1 through 9 of this document.\n\n   \"Licensor\" shall mean the copyright owner or entity authorized by\n   the copyright owner that is granting the License.\n\n   \"Legal Entity\" shall mean the union of the acting entity and all\n   other entities that control, are controlled by, or are under common\n   control with that entity. For the purposes of this definition,\n   \"control\" means (i) the power, direct or indirect, to cause the\n   direction or management of such entity, whether by contract or\n   otherwise, or (ii) ownership of fifty percent (50%) or more of the\n   outstanding shares, or (iii) beneficial ownership of such entity.\n\n   \"You\" (or \"Your\") shall mean an individual or Legal Entity\n   exercising permissions granted by this License.\n\n   \"Source\" form shall mean the preferred form for making modifications,\n   including but not limited to software source code, documentation\n   source, and configuration files.\n\n   \"Object\" form shall mean any form resulting from mechanical\n   transformation or translation of a Source form, including but\n   not limited to compiled object code, generated documentation,\n   and conversions to other media types.\n\n   \"Work\" shall mean the work of authorship, whether in Source or\n   Object form, made available under the License, as indicated by a\n   copyright notice that is included in or attached to the work\n   (an example is provided in the Appendix below).\n\n   \"Derivative Works\" shall mean any work, whether in Source or Object\n   form, that is based on (or derived from) the Work and for which the\n   editorial revisions, annotations, elaborations, or other modifications\n   represent, as a whole, an original work of authorship. For the purposes\n   of this License, Derivative Works shall not include works that remain\n   separable from, or merely link (or bind by name) to the interfaces of,\n   the Work and Derivative Works thereof.\n\n   \"Contribution\" shall mean any work of authorship, including\n   the original version of the Work and any modifications or additions\n   to that Work or Derivative Works thereof, that is intentionally\n   submitted to Licensor for inclusion in the Work by the copyright owner\n   or by an individual or Legal Entity authorized to submit on behalf of\n   the copyright owner. For the purposes of this definition, \"submitted\"\n   means any form of electronic, verbal, or written communication sent\n   to the Licensor or its representatives, including but not limited to\n   communication on electronic mailing lists, source code control systems,\n   and issue tracking systems that are managed by, or on behalf of, the\n   Licensor for the purpose of discussing and improving the Work, but\n   excluding communication that is conspicuously marked or otherwise\n   designated in writing by the copyright owner as \"Not a Contribution.\"\n\n   \"Contributor\" shall mean Licensor and any individual or Legal Entity\n   on behalf of whom a Contribution has been received by Licensor and\n   subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   copyright license to reproduce, prepare Derivative Works of,\n   publicly display, publicly perform, sublicense, and distribute the\n   Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   (except as stated in this section) patent license to make, have made,\n   use, offer to sell, sell, import, and otherwise transfer the Work,\n   where such license applies only to those patent claims licensable\n   by such Contributor that are necessarily infringed by their\n   Contribution(s) alone or by combination of their Contribution(s)\n   with the Work to which such Contribution(s) was submitted. If You\n   institute patent litigation against any entity (including a\n   cross-claim or counterclaim in a lawsuit) alleging that the Work\n   or a Contribution incorporated within the Work constitutes direct\n   or contributory patent infringement, then any patent licenses\n   granted to You under this License for that Work shall terminate\n   as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n   Work or Derivative Works thereof in any medium, with or without\n   modifications, and in Source or Object form, provided that You\n   meet the following conditions:\n\n   (a) You must give any other recipients of the Work or\n       Derivative Works a copy of this License; and\n\n   (b) You must cause any modified files to carry prominent notices\n       stating that You changed the files; and\n\n   (c) You must retain, in the Source form of any Derivative Works\n       that You distribute, all copyright, patent, trademark, and\n       attribution notices from the Source form of the Work,\n       excluding those notices that do not pertain to any part of\n       the Derivative Works; and\n\n   (d) If the Work includes a \"NOTICE\" text file as part of its\n       distribution, then any Derivative Works that You distribute must\n       include a readable copy of the attribution notices contained\n       within such NOTICE file, excluding those notices that do not\n       pertain to any part of the Derivative Works, in at least one\n       of the following places: within a NOTICE text file distributed\n       as part of the Derivative Works; within the Source form or\n       documentation, if provided along with the Derivative Works; or,\n       within a display generated by the Derivative Works, if and\n       wherever such third-party notices normally appear. The contents\n       of the NOTICE file are for informational purposes only and\n       do not modify the License. You may add Your own attribution\n       notices within Derivative Works that You distribute, alongside\n       or as an addendum to the NOTICE text from the Work, provided\n       that such additional attribution notices cannot be construed\n       as modifying the License.\n\n   You may add Your own copyright statement to Your modifications and\n   may provide additional or different license terms and conditions\n   for use, reproduction, or distribution of Your modifications, or\n   for any such Derivative Works as a whole, provided Your use,\n   reproduction, and distribution of the Work otherwise complies with\n   the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n   any Contribution intentionally submitted for inclusion in the Work\n   by You to the Licensor shall be under the terms and conditions of\n   this License, without any additional terms or conditions.\n   Notwithstanding the above, nothing herein shall supersede or modify\n   the terms of any separate license agreement you may have executed\n   with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n   names, trademarks, service marks, or product names of the Licensor,\n   except as required for reasonable and customary use in describing the\n   origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n   agreed to in writing, Licensor provides the Work (and each\n   Contributor provides its Contributions) on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n   implied, including, without limitation, any warranties or conditions\n   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n   PARTICULAR PURPOSE. You are solely responsible for determining the\n   appropriateness of using or redistributing the Work and assume any\n   risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n   whether in tort (including negligence), contract, or otherwise,\n   unless required by applicable law (such as deliberate and grossly\n   negligent acts) or agreed to in writing, shall any Contributor be\n   liable to You for damages, including any direct, indirect, special,\n   incidental, or consequential damages of any character arising as a\n   result of this License or out of the use or inability to use the\n   Work (including but not limited to damages for loss of goodwill,\n   work stoppage, computer failure or malfunction, or any and all\n   other commercial damages or losses), even if such Contributor\n   has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n   the Work or Derivative Works thereof, You may choose to offer,\n   and charge a fee for, acceptance of support, warranty, indemnity,\n   or other liability obligations and/or rights consistent with this\n   License. However, in accepting such obligations, You may act only\n   on Your own behalf and on Your sole responsibility, not on behalf\n   of any other Contributor, and only if You agree to indemnify,\n   defend, and hold each Contributor harmless for any liability\n   incurred by, or claims asserted against, such Contributor by reason\n   of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n   To apply the Apache License to your work, attach the following\n   boilerplate notice, with the fields enclosed by brackets \"[]\"\n   replaced with your own identifying information. (Don't include\n   the brackets!)  The text should be enclosed in the appropriate\n   comment syntax for the file format. We also recommend that a\n   file or class name and description of purpose be included on the\n   same \"printed page\" as the copyright notice for easier\n   identification within third-party archives.\n\nCopyright 2017 Denis Kolodin\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "Copyright (c) 2017 Denis Kolodin\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile.toml",
    "content": "######################\n#\n# public tasks:\n# * checks-flow\n#   * lint\n#   * lint-release\n#   * format\n# * test-flow\n#   * test\n#   * doc-test\n#   * website-test\n#\n# packages/yew also contains `clippy-feature-soundness` (requires cargo-hack)\n# Run `cargo make --list-all-steps` for more details.\n#\n######################\n[config]\nmin_version = \"0.32.4\"\nskip_core_tasks = true\ndefault_to_workspace = false\n\n[env]\nCARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true\nCARGO_MAKE_CLIPPY_ARGS = \"-- --deny=warnings\"\nCARGO_MAKE_WORKSPACE_SKIP_MEMBERS = [\n    \"examples/*\",\n    \"tools/*\",\n]\n\n[config.modify_core_tasks]\nprivate = true\nnamespace = \"core\"\n\n# checks\n\n[tasks.lint]\ncategory = \"Checks\"\ndescription = \"Runs clippy\"\ncommand = \"cargo\"\nargs = [\"clippy\", \"--\", \"--deny=warnings\"]\n\n# Needed, because we have some code differences between debug and release builds\n[tasks.lint-release]\ncategory = \"Checks\"\ncommand = \"cargo\"\nargs = [\"clippy\", \"--all-targets\", \"--release\", \"--\", \"--deny=warnings\"]\n\n[tasks.format]\ncategory = \"Checks\"\ntoolchain = \"nightly\"\nenv = { CARGO_MAKE_RUST_CHANNEL = \"nightly\" }\n\n\n[tasks.checks-flow]\ncategory = \"Checks\"\ndescription = \"Runs clippy in debug and release mode and format all the code\"\nrun_task = { name = [\"lint\", \"lint-release\", \"format\"], fork = true }\n\n# Tests\n\n[tasks.test]\ncommand = \"cargo\"\nargs = [\"test\", \"--all-targets\"]\nworkspace = true\n\n[tasks.doc-test]\ncommand = \"cargo\"\nargs = [\"test\", \"--doc\", \"--all-features\"]\nworkspace = true\n\n[tasks.website-test]\ncommand = \"cargo\"\nargs = [\"test\", \"-p\", \"website-test\"]\n\n[tasks.test-flow]\ncategory = \"Testing\"\ndescription = \"Run all tests\"\nrun_task = { name = [\"test\", \"doc-test\", \"website-test\"], fork = true, parallel = true }\n\n# misc\n\n[tasks.generate-change-log]\ncategory = \"Maintainer processes\"\ntoolchain = \"stable\"\ncommand = \"cargo\"\nargs = [\"run\", \"-p\", \"changelog\", \"--release\", \"${@}\"]\n\n[tasks.default]\n#run_task = { name = [\"checks-flow\", \"test-flow\"], fork = true }\ndependencies = [\"checks-flow\", \"test-flow\"]\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <a href=\"https://yew.rs/\" target=\"_blank\"><img src=\"https://yew.rs/img/logo.png\" width=\"150\" /></a>\n\n  <h1>Yew</h1>\n\n  <p>\n    <strong>Rust / Wasm client web app framework</strong>\n  </p>\n\n  <p>\n    <a href=\"https://crates.io/crates/yew\"><img alt=\"Crate Info\" src=\"https://img.shields.io/crates/v/yew.svg\"/></a>\n    <a href=\"https://docs.rs/yew/\"><img alt=\"API Docs\" src=\"https://img.shields.io/badge/docs.rs-yew-green\"/></a>\n    <a href=\"https://discord.gg/VQck8X4\"><img alt=\"Discord Chat\" src=\"https://img.shields.io/discord/701068342760570933\"/></a>\n  </p>\n\n  <h4>\n    <a href=\"https://yew.rs/\">Documentation (stable)</a>\n    <span> | </span>\n    <a href=\"https://yew.rs/docs/next/\">Documentation (latest)</a>\n    <span> | </span>\n    <a href=\"https://github.com/yewstack/yew/tree/master/examples\">Examples</a>\n    <span> | </span>\n    <a href=\"https://github.com/yewstack/yew/blob/master/CHANGELOG.md\">Changelog</a>\n    <span> | </span>\n    <a href=\"https://yew.rs/docs/more/roadmap\">Roadmap</a>\n    <span> | </span>\n    <a href=\"https://yew.rs/zh-Hans\">简体中文文档</a>\n    <span> | </span>\n    <a href=\"https://yew.rs/zh-Hant\">繁體中文文檔</a>\n    <span> | </span>\n    <a href=\"https://yew.rs/ja\">ドキュメント</a>\n  </h4>\n</div>\n\n## About\n\n**Yew** is a modern Rust framework for creating multi-threaded, front-end web apps with WebAssembly.\n\n* Features a macro for declaring interactive HTML with Rust expressions. Developers who have experience using JSX in React should feel quite at home when using Yew.\n* Achieves high performance by minimizing DOM API calls for each page render and by making it easy to offload processing to background web workers.\n* Supports JavaScript interoperability, allowing developers to leverage NPM packages and integrate with existing JavaScript applications.\n\nYew is named after a type of evergreen tree, and is pronounced /juː/. [Entry with audio on Cambridge Dictionary](https://dictionary.cambridge.org/dictionary/english/yew).\n\n*Note: Yew is not 1.0 yet. Be prepared to do major refactoring due to breaking API changes.*\n\n## Contributing\n\nYew is a community-driven effort and we welcome all kinds of contributions, big or small, from developers of all backgrounds. We want the Yew community to be a fun and friendly place, so please review our [Code of Conduct](https://github.com/yewstack/yew/blob/master/CODE_OF_CONDUCT.md) to learn what behavior will not be tolerated.\n\n#### 🤠 New to Yew?\n\nStart learning about the framework by helping us improve our [documentation](https://github.com/yewstack/yew/tree/master/website/docs). Pull requests which improve test coverage are also very welcome.\n\n#### 😎 Looking for inspiration?\n\nCheck out the community curated list of awesome things related to Yew / WebAssembly at [jetli/awesome-yew](https://github.com/jetli/awesome-yew).\n\n#### 🤔 Confused about something?\n\nFeel free to drop into our [Discord chatroom](https://discord.gg/VQck8X4) or open a [new \"Question\" issue](https://github.com/yewstack/yew/issues/new/choose) to get help from contributors. Often questions lead to improvements to the ergonomics of the framework, better documentation and even new features!\n\n#### 🙂 Ready to dive into the code?\n\nAfter reviewing the [Contribution Guide](https://github.com/yewstack/yew/blob/master/CONTRIBUTING.md), check out the [\"Good First Issues\"](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) (they are eager for attention!). Once you find one that interests you, feel free to assign yourself to an issue and don't hesitate to reach out for guidance, the issues vary in complexity.\n\n#### 😱 Found a bug?\n\nPlease [report all bugs!](https://github.com/yewstack/yew/issues/new/choose) We are happy to help support developers fix the bugs they find if they are interested and have the time.\n\n## Contributors\n\n### Code Contributors\n\nThis project exists thanks to all the people who contribute.\n<a href=\"https://github.com/yewstack/yew/graphs/contributors\"><img src=\"https://opencollective.com/yew/contributors.svg?width=890&button=false\" /></a>\n\n### Financial Contributors\n\nBecome a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/yew/contribute)]\n\n#### Individuals\n\n<a href=\"https://opencollective.com/yew\"><img src=\"https://opencollective.com/yew/individuals.svg?width=890\"></a>\n\n#### Organizations\n\nSupport this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/yew/contribute)]\n\n<a href=\"https://opencollective.com/yew/organization/0/website\"><img src=\"https://opencollective.com/yew/organization/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/1/website\"><img src=\"https://opencollective.com/yew/organization/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/2/website\"><img src=\"https://opencollective.com/yew/organization/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/3/website\"><img src=\"https://opencollective.com/yew/organization/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/4/website\"><img src=\"https://opencollective.com/yew/organization/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/5/website\"><img src=\"https://opencollective.com/yew/organization/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/6/website\"><img src=\"https://opencollective.com/yew/organization/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/7/website\"><img src=\"https://opencollective.com/yew/organization/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/8/website\"><img src=\"https://opencollective.com/yew/organization/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/yew/organization/9/website\"><img src=\"https://opencollective.com/yew/organization/9/avatar.svg\"></a>\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Reporting a Vulnerability\n\nPlease do not create a GitHub issue for security vulnerabilities, Instead do the following:\n\n1. Click on the **Security** tab and then click on the **\"Report a Vulnerability\"** button.\n\n![Report a Vulnerability](https://github.com/shubhsharma19/yew/assets/69891912/810b0297-65c0-42e1-9935-08f026387bf7)\n\n2. After that give a **title** and a **description**. \n\n![Title and Description](https://github.com/shubhsharma19/yew/assets/69891912/3686459b-c7b4-49ea-92cf-5313c4ccd756)\n\n\nWhen reporting the vulnerability, please provide the following information, if possible:\n\n- **MCVE (Minimum Complete Verifiable Example)**: Please include a concise code snippet that demonstrates the error in a simplified manner.\n\n- **Versions of Yew**: Specify the versions of Yew in which the vulnerability is present. This helps us narrow down the scope of the issue and assess its impact accurately.\n\n- **Impact and Severity**: Describe the effects of the vulnerability and its seriousness. Provide details about any potential risks, security breaches, or the impact it may have on the system.\n\n> For contacting the maintainers, you can reach out to them via email at maintainers@yew.rs\n"
  },
  {
    "path": "_typos.toml",
    "content": "[files]\nextend-exclude = [\"examples/router/data/syllables.txt\", \"examples/function_router/data/syllables.txt\"]\n\n[default.extend-words]\nba = \"ba\"\n"
  },
  {
    "path": "api-docs/.gitignore",
    "content": "dist\n"
  },
  {
    "path": "api-docs/before-content.html",
    "content": "<div id=\"unreleased-version-header\">\n    <div>This is unreleased documentation for Yew Next version.</div>\n    <div>For up-to-date documentation, see <a href=\"https://docs.rs/yew\">the latest version on docs.rs</a>.</div>\n</div>\n"
  },
  {
    "path": "api-docs/styles.css",
    "content": "#unreleased-version-header {\n    background-color: rgb(200, 237, 248);\n    z-index: 400;\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    height: 70px;\n    padding-top: 10px;\n    padding-bottom: 10px;\n    text-align: center;\n    font-family: sans-serif;\n    box-shadow: 0 0 5px 0 rgb(100, 100, 100);\n}\n\n@media (prefers-color-scheme: dark) {\n    #unreleased-version-header {\n        background-color: rgb(32, 43, 57);\n        box-shadow: 0 0 5px 0 black;\n    }\n}\n\nbody {\n    padding-top: 70px !important;\n}\n"
  },
  {
    "path": "ci/collect_sizes.py",
    "content": "from typing import Dict, List, Optional\nfrom pathlib import Path\n\nimport glob\nimport os\nimport json\n\n\ndef find_example_sizes(parent_dir: Path) -> Dict[str, int]:\n    example_sizes: Dict[str, int] = {}\n\n    for example_dist_dir in (parent_dir / \"dist\").iterdir():\n\n        total_size = 0\n\n        # For examples with multiple bundles, we add them together.\n        for bundle in example_dist_dir.glob(f\"*.wasm\"):\n            size = bundle.stat().st_size\n\n            print(f\"{bundle} has a size of {size}.\")\n\n            total_size += size\n\n        if total_size > 0:\n            example_sizes[example_dist_dir.name] = total_size\n\n    return example_sizes\n\n\ndef main() -> None:\n    sizes = find_example_sizes(Path.cwd())\n\n    size_cmp_info = {\n        \"sizes\": sizes,\n        \"issue_number\": os.environ[\"ISSUE_NUMBER\"],\n    }\n\n    with open(\".SIZE_CMP_INFO\", \"w+\") as f:\n        f.write(json.dumps(size_cmp_info, indent=4))\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "ci/install-wasm-bindgen-cli.sh",
    "content": "#!/usr/bin/env bash\nif [ ! -f \"Cargo.lock\" ]; then\n  cargo fetch\nfi\n\nVERSION=$(cargo pkgid --frozen wasm-bindgen | cut -d \":\" -f 3)\n\n# Cargo decided to change syntax after 1.61\nif [ \"$VERSION\" = \"\" ]; then\n  VERSION=$(cargo pkgid --frozen wasm-bindgen | cut -d \"@\" -f 2)\nfi\n\nif [ \"$(wasm-bindgen --version)\" != \"wasm-bindgen $VERSION\" ]; then\n  cargo +stable install --version \"$VERSION\" wasm-bindgen-cli --force\nfi\n"
  },
  {
    "path": "ci/make_benchmark_ssr_cmt.py",
    "content": "from typing import Dict, List, Optional, Tuple\n\nimport os\nimport json\n\n\nheader = \"| Benchmark | Round | Min (ms) | Max (ms) | Mean (ms) | Standard Deviation |\"\nsep = \"| --- | --- | --- | --- | --- | --- |\"\n\n\ndef write_benchmark(lines: List[str], content: List[Dict[str, str]]) -> None:\n    lines.append(\"<details>\")\n    lines.append(\"\")\n    lines.append(header)\n    lines.append(sep)\n\n    for i in content:\n        lines.append(\n            f\"| {i['name']} | {i['round']} | {i['min']} | {i['max']} | {i['mean']} | {i['std_dev']} |\"\n        )\n\n    lines.append(\"\")\n    lines.append(\"</details>\")\n    lines.append(\"\")\n\n\ndef main() -> None:\n    with open(\"benchmark-ssr/yew-master/tools/output.json\") as f:\n        master_content = json.loads(f.read())\n\n    with open(\"benchmark-ssr/current-pr/tools/output.json\") as f:\n        pr_content = json.loads(f.read())\n\n    lines: List[str] = []\n\n    lines.append(\"### Benchmark - SSR\")\n    lines.append(\"\")\n\n    lines.append(\"#### Yew Master\")\n    lines.append(\"\")\n\n    write_benchmark(lines, master_content)\n\n    lines.append(\"#### Pull Request\")\n    lines.append(\"\")\n\n    write_benchmark(lines, pr_content)\n\n    output = \"\\n\".join(lines)\n\n    with open(os.environ[\"GITHUB_ENV\"], \"a+\") as f:\n        f.write(f\"YEW_BENCH_SSR={json.dumps(output)}\\n\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "ci/make_example_size_cmt.py",
    "content": "from typing import Dict, List, Optional, Tuple\n\nimport os\nimport json\n\n\nheader = \"| examples | master (KB) | pull request (KB) | diff (KB) | diff (%) |\"\nsep = \"| --- | --- | --- | --- | --- |\"\n\n\ndef format_size(size: Optional[int]) -> str:\n    if size is None:\n        return \"N/A\"\n\n    if size == 0:\n        return \"0\"\n\n    return f\"{size / 1024:.3f}\"\n\n\ndef format_diff_size(\n    master_size: Optional[int], pr_size: Optional[int]\n) -> Tuple[str, str, bool]:\n    if master_size is None or pr_size is None:\n        return (\"N/A\", \"N/A\", False)\n\n    diff = pr_size - master_size\n\n    if diff == 0:\n        return (\"0\", \"0.000%\", False)\n\n    diff_percent = diff / master_size\n\n    return (f\"{diff / 1024:+.3f}\", f\"{diff_percent:+.3%}\", abs(diff_percent) >= 0.01)\n\n\ndef main() -> None:\n    with open(\"size-cmp-pr-info/.SIZE_CMP_INFO\") as f:\n        pr_content = json.loads(f.read())\n\n    with open(\"size-cmp-master-info/.SIZE_CMP_INFO\") as f:\n        master_content = json.loads(f.read())\n\n    master_sizes: dict[str, int] = master_content[\"sizes\"]\n    pr_sizes: dict[str, int] = pr_content[\"sizes\"]\n\n    example_names = sorted(set([*master_sizes.keys(), *pr_sizes.keys()]))\n    joined_sizes = [(i, [master_sizes.get(i), pr_sizes.get(i)]) for i in example_names]\n\n    assert pr_content[\"issue_number\"] == master_content[\"issue_number\"], \\\n        \"Issue number differs between master and pr?\"\n\n    issue_number = pr_content[\"issue_number\"]\n\n    lines: List[str] = []\n    significant_lines: List[str] = []\n\n    lines.append(\"### Size Comparison\")\n    lines.append(\"\")\n    lines.append(\"<details>\")\n    lines.append(\"\")\n    lines.append(header)\n    lines.append(sep)\n\n    for (i, sizes) in joined_sizes:\n        (master_size, pr_size) = sizes\n\n        master_size_str = format_size(master_size)\n        pr_size_str = format_size(pr_size)\n\n        (diff_str, diff_percent, diff_significant) = format_diff_size(\n            master_size, pr_size\n        )\n\n        line_str = (\n            f\"| {i} | {master_size_str} | {pr_size_str} | \"\n            f\"{diff_str} | {diff_percent} |\"\n        )\n\n        lines.append(line_str)\n\n        if diff_significant:\n            significant_lines.append(line_str)\n\n    lines.append(\"\")\n    lines.append(\"</details>\")\n    lines.append(\"\")\n\n    if significant_lines:\n\n        if len(significant_lines) == 1:\n            lines.append(\"⚠️ The following example has changed its size significantly:\")\n        else:\n            lines.append(\n                \"⚠️ The following examples have changed their size significantly:\"\n            )\n        lines.append(\"\")\n\n        lines.append(header)\n        lines.append(sep)\n        lines.extend(significant_lines)\n\n    else:\n        lines.append(\"✅ None of the examples has changed their size significantly.\")\n\n    output = \"\\n\".join(lines)\n\n    with open(os.environ[\"GITHUB_ENV\"], \"a+\") as f:\n        f.write(f\"YEW_EXAMPLE_SIZES={json.dumps(output)}\\n\")\n        f.write(f\"PR_NUMBER={issue_number}\\n\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "ci/write-min-size-flags.sh",
    "content": "#!/usr/bin/env bash\ncat examples/.cargo/min-size-config.toml >> examples/.cargo/dummy-min-size-config.toml\n"
  },
  {
    "path": "examples/.cargo/config.toml",
    "content": "include = [\"dummy-min-size-config.toml\"]\n"
  },
  {
    "path": "examples/.cargo/dummy-min-size-config.toml",
    "content": "# This file is intentionally left empty.\n# It gets filled by `min-size-config.toml` in some cases by CI\n"
  },
  {
    "path": "examples/.cargo/min-size-config.toml",
    "content": "[unstable]\nbuild-std = [\"core\", \"std\", \"panic_abort\"]\nbuild-std-features = [\"optimize_for_size\"]\n\n[target.'cfg(target_arch = \"wasm32\")']\nrustflags = [\"-Zunstable-options\", \"-Cpanic=immediate-abort\", \"--cfg\", \"nightly_yew\"]\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "# trunk output\ndist/\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Yew Examples\n\n## How to Run\n\nThe examples are built with [trunk](https://github.com/thedodd/trunk).\nOnce you have the development environment fully set up (see [documentation](https://yew.rs/docs/next/getting-started/introduction)),\nrunning an example is as easy as running a single command:\n\n```bash\n# move into the directory of the example you want to run\n# In this case it's the todomvc example\ncd examples/todomvc\n\n# build and serve the example\ntrunk serve --open\n```\n\nSome examples using the `rand` crate require a special rust flag to be enabled:\n\n```bash\nRUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' trunk serve --open\n```\n\nSome examples may perform better using the `release` profile. If something is slow, you can try running it with the `--release` argument.\n\nWe're also publicly hosting the examples at `https://examples.yew.rs/<EXAMPLE>`.\nAs an example, check out the TodoMVC example here: <https://examples.yew.rs/todomvc>\n\n## List of Examples\n\n| Example                                                                                   | [CT] | Description                                                                                                                         |\n| ----------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------- |\n| [async_clock](async_clock)                                                                | [S]  | Demonstrates the use of asynchronous tasks in a yew component.                                                                      |\n| [boids](boids)                                                                            | [S]  | Yew port of [Boids](https://en.wikipedia.org/wiki/Boids)                                                                            |\n| [communication_child_to_parent](communication_child_to_parent)                            | [S]  | Communication from child to parent components.                                                                                      |\n| [communication_grandchild_with_grandparent](communication_grandchild_with_grandparent)    | [S]  | Communication from grandchildren to grandparent components.                                                                         |\n| [communication_grandparent_to_grandchild](communication_grandparent_to_grandchild)        | [S]  | Communication from grandparent to grandchild components.                                                                            |\n| [communication_parent_to_child](communication_parent_to_child)                            | [S]  | Communication from parent to child components.                                                                                      |\n| [contexts](contexts)                                                                      | [F]  | A technical demonstration of the Context API.                                                                                       |\n| [counter](counter)                                                                        | [S]  | Simple counter which can be incremented and decremented.                                                                            |\n| [counter_functional](counter_functional)                                                  | [F]  | Simple counter which can be incremented and decremented made using function components.                                             |\n| [dyn_create_destroy_apps](dyn_create_destroy_apps)                                        | [S]  | Uses the function `Renderer::with_root_and_props` and the `AppHandle` struct to dynamically create and delete Yew apps.             |\n| [file_upload](file_upload)                                                                | [S]  | Uses [`gloo::file`](https://docs.rs/gloo-file/latest/gloo_file/index.html) to read the content of user uploaded files.              |\n| [function_delayed_input](function_delayed_input)                                          | [F]  | Demonstrates how to implement a form with delayed input processing.                                                                 |\n| [function_memory_game](function_memory_game)                                              | [F]  | Implementation of [Memory Game](https://github.com/bradlygreen/Memory-Game).                                                        |\n| [function_router](function_router)                                                        | [F]  | Identical to [`router`](router) but using function components.                                                                      |\n| [function_todomvc](function_todomvc)                                                      | [F]  | Implementation of [TodoMVC](http://todomvc.com/) using function components and hooks.                                               |\n| [futures](futures)                                                                        | [S]  | Demonstrates how you can use futures and async code with Yew. Features a Markdown renderer.                                         |\n| [game_of_life](game_of_life)                                                              | [S]  | Implementation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life).                                   |\n| [immutable](immutable)                                                                    | [SF] | Using immutable types in components.                                                                                                |\n| [inner_html](inner_html)                                                                  | [S]  | Embeds an external document as raw HTML by manually managing the element.                                                           |\n| [js_callback](js_callback)                                                                | [F]  | Interacts with JavaScript code.                                                                                                     |\n| [keyed_list](keyed_list)                                                                  | [S]  | Demonstrates how to use keys to improve the performance of lists.                                                                   |\n| [mount_point](mount_point)                                                                | [S]  | Shows how to mount the root component to a custom element.                                                                          |\n| [nested_list](nested_list)                                                                | [S]  | Renders a styled list which tracks hover events.                                                                                    |\n| [node_refs](node_refs)                                                                    | [S]  | Uses a [`NodeRef`](https://yew.rs/docs/concepts/components/refs) to focus the input element under the cursor.                       |\n| [password_strength](password_strength)                                                    | [SF] | A password strength estimator implemented in Yew.                                                                                   |\n| [portals](portals)                                                                        | [S]  | Renders elements into out-of-tree nodes with the help of portals.                                                                   |\n| [router](router)                                                                          | [S]  | The best yew blog built with `yew-router`.                                                                                          |\n| [simple_ssr](simple_ssr)                                                                  | [F]  | Demonstrates server-side rendering.                                                                                                 |\n| [ssr_router](ssr_router)                                                                  | [F]  | Demonstrates server-side rendering with routing.                                                                                    |\n| [suspense](suspense)                                                                      | [F]  | This is an example that demonstrates `<Suspense />` support.                                                                        |\n| [timer](timer)                                                                            | [S]  | Demonstrates the use of the interval and timeout services.                                                                          |\n| [timer_functional](timer_functional)                                                      | [F]  | Demonstrates the use of the interval and timeout services using function components                                                 |\n| [todomvc](todomvc)                                                                        | [S]  | Implementation of [TodoMVC](http://todomvc.com/).                                                                                   |\n| [two_apps](two_apps)                                                                      | [S]  | Runs two separate Yew apps which can communicate with each other.                                                                   |\n| [web_worker_fib](web_worker_fib)                                                          | [F]  | Calculate Fibonacci numbers in a web worker thread using [`yew-agent`](https://docs.rs/yew-agent/latest/yew_agent/).              |\n| [web_worker_prime](web_worker_prime)                                                      | [F]  | Calculate Prime numbers in a web worker thread using [`yew-agent`](https://docs.rs/yew-agent/latest/yew_agent/).                  |\n| [webgl](webgl)                                                                            | [S]  | Controls a [WebGL canvas](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL) from Yew. |\n| [wasi_ssr_module](wasi_ssr_module)                                                        | [F]  | Demonstrates server-side rendering using WASI.                                                                                      |\n\n[CT]: ## \"Component Type\"\n[S]: ## \"Struct Components\"\n[F]: ## \"Function Components\"\n[SF]: ## \"Struct and Function Components\"\n\n## Next Steps\n\nHave a look at Yew's [starter templates](https://yew.rs/docs/getting-started/build-a-sample-app#using-a-starter-template) when starting a project using Yew – they can significantly simplify things.\n\n## Helping Out\n\nIf one of the examples catches your interest, look for the \"improvements\" section in its `README.md` file.\nMost examples list a few ideas for how to improve them.\nConsider starting with those but don't hesitate to improve an example in other ways either.\n\nOne problem that currently plagues most examples is the lack of styling.\nPlease help us make the examples look as flashy as possible!\n"
  },
  {
    "path": "examples/async_clock/Cargo.toml",
    "content": "[package]\nname = \"async_clock\"\nversion = \"0.0.1\"\nauthors = [\"Marcel Ibes <mibes@mibesco.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nchrono.workspace = true\nfutures.workspace = true\ngloo-net = \"0.6\"\n"
  },
  {
    "path": "examples/async_clock/README.md",
    "content": "# Asynchronous coding in Yew\n\nAn example of using asynchronous tasks in a component. This example creates a clock in the background and\ncontinuously awaits clock-ticks. When the clock updates the new time is sent to the UI component to display.\nIn parallel it fetches online jokes to make the clock more entertaining to watch.\n\nIts main purpose is to demonstrate various ways of using async code in a yew component. It uses the following async\nfeatures:\n- send_future\n- send_stream\n- spawn_local\n- mpsc::unbounded channels\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/async_clock/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/async_clock/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Async Examples</title>\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/async_clock/index.scss",
    "content": "body {\n    font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;\n    font-size: 16pt;\n}\n\n.app {\n    display: flex;\n    justify-content: center;\n    flex-direction: row;\n}\n\n.time-display {\n    display: flex;\n    justify-content: center;\n    color: darkblue;\n    font-size: 24pt;\n    font-weight: bold;\n    margin-bottom: 15px;\n}\n\n.joke-display {\n    display: flex;\n    justify-content: center;\n    color: orangered;\n    max-width: 75%;\n    border-color: darkblue;\n    border-style: dashed;\n    border-width: 1px;\n    padding: 10px;\n}\n\n.fun-score-display {\n    font-style: italic;\n}\n\n\n.clock {\n  display: flex;\n  flex-direction: column;\n  row-gap: 15px;\n  align-items: center;\n}\n"
  },
  {
    "path": "examples/async_clock/src/main.rs",
    "content": "use chrono::{DateTime, Local};\nuse futures::{FutureExt, StreamExt};\nuse services::compute_fun_score;\nuse yew::platform::pinned::mpsc::UnboundedSender;\nuse yew::{html, AttrValue, Component, Context, Html};\n\nuse crate::services::{emit_jokes, initialize_atomic_clocks, stream_time};\n\nmod services;\n\n/// The AsyncComponent displays the current time and some silly jokes. Its main purpose is to\n/// demonstrate the use of async code in a yew component. It uses the following async features:\n/// - send_future\n/// - send_stream\n/// - spawn_local\n/// - mpsc::unbounded channels\npub struct AsyncComponent {\n    clock: Option<AttrValue>,\n    joke: Option<AttrValue>,\n    fun_score: Option<i16>,\n    fun_score_channel: UnboundedSender<AttrValue>,\n}\n\npub enum Msg {\n    ClockInitialized(()),\n    ClockTicked(DateTime<Local>),\n    Joke(AttrValue),\n    FunScore(i16),\n}\n\nimpl Component for AsyncComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        // Demonstrate how we can send a message to the component when a future completes.\n        // This is the most straightforward way to use async code in a yew component.\n        let is_initialized = initialize_atomic_clocks();\n        ctx.link()\n            .send_future(is_initialized.map(Msg::ClockInitialized));\n\n        // The compute_fun_score launches a background task that is ready to compute the fun score\n        // from jokes that are delivered on this channel. The outcome of the computation is\n        // sent back to the component via the Msg::FunScore callback.\n        let fun_score_cb = ctx.link().callback(Msg::FunScore);\n        let fun_score_channel = compute_fun_score(fun_score_cb);\n\n        Self {\n            clock: None,\n            joke: None,\n            fun_score: None,\n            fun_score_channel,\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ClockTicked(current_time) => {\n                // Update the clock display\n                self.clock = Some(AttrValue::from(current_time.to_rfc2822()));\n            }\n            Msg::ClockInitialized(_) => {\n                // Now that the clock is initialized, we can start the time stream.\n                self.clock = Some(AttrValue::from(\"Initialized\"));\n\n                // The stream_time method returns a stream of time updates. We use send_stream to\n                // update the component with a Msg::ClockTicked message every time\n                // the stream produces a new value.\n                let time_steam = stream_time();\n                ctx.link().send_stream(time_steam.map(Msg::ClockTicked));\n\n                // In parallel we launch a background task that produces jokes to make the clock\n                // more fun to watch. The jokes are emitted back to the component\n                // through the Msg::Joke callback.\n                let joke_cb = ctx.link().callback(Msg::Joke);\n                emit_jokes(joke_cb);\n            }\n            Msg::Joke(joke) => {\n                // Update the joke\n                self.joke = Some(joke.clone());\n\n                // Reset the fun score\n                self.fun_score = None;\n\n                // Send the joke to the background task that computes the fun score.\n                self.fun_score_channel\n                    .send_now(joke)\n                    .expect(\"failed to send joke\");\n            }\n            Msg::FunScore(score) => {\n                self.fun_score = Some(score);\n            }\n        }\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let display = self.clock.as_deref().unwrap_or(\"Loading...\");\n        let joke = self.joke.as_deref().unwrap_or(\"Loading...\");\n        let fun_score = self\n            .fun_score\n            .map(|score| format!(\"Fun score: {score}\"))\n            .unwrap_or_else(|| \"Computing...\".to_string());\n\n        html! {\n            <div class=\"app\">\n                <div class=\"clock\">\n                    <h2>{ \"Asynchronous Examples\" }</h2>\n                    <div class=\"time-display\">\n                        { display }\n                    </div>\n                    <div class=\"joke-display\">\n                        { joke }\n                    </div>\n                    <div class=\"fun-score-display\">\n                        { fun_score }\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<AsyncComponent>::new().render();\n}\n"
  },
  {
    "path": "examples/async_clock/src/services.rs",
    "content": "use std::time::Duration;\n\nuse chrono::{DateTime, Local};\nuse futures::{Stream, StreamExt};\nuse gloo_net::http::Request;\nuse yew::platform::pinned::mpsc::UnboundedSender;\nuse yew::platform::spawn_local;\nuse yew::platform::time::{interval, sleep};\nuse yew::{AttrValue, Callback};\n\nconst ONE_SEC: Duration = Duration::from_secs(1);\nconst TEN_SECS: Duration = Duration::from_secs(10);\n\n/// Demonstration code to show how to use async code in a yew component.\npub async fn initialize_atomic_clocks() {\n    // aligning with atomic clocks :-)\n    sleep(ONE_SEC).await;\n}\n\n/// Returns a stream of time updates.\npub fn stream_time() -> impl Stream<Item = DateTime<Local>> {\n    interval(ONE_SEC).map(|_| Local::now())\n}\n\n/// Emit entertaining jokes every 10 seconds.\npub fn emit_jokes(joke_cb: Callback<AttrValue>) {\n    // Spawn a background task that will fetch a joke and send it to the component.\n    spawn_local(async move {\n        loop {\n            // Fetch the online joke\n            let fun_fact =\n                Request::get(\"https://v2.jokeapi.dev/joke/Programming?format=txt&safe-mode\")\n                    .send()\n                    .await\n                    .unwrap()\n                    .text()\n                    .await\n                    .unwrap();\n\n            // Emit it to the component\n            joke_cb.emit(AttrValue::from(fun_fact));\n            sleep(TEN_SECS).await;\n        }\n    });\n}\n\n/// Background task that computes the fun score from jokes that are delivered on the channel.\npub fn compute_fun_score(fun_score_cb: Callback<i16>) -> UnboundedSender<AttrValue> {\n    let (tx, mut rx) = yew::platform::pinned::mpsc::unbounded::<AttrValue>();\n\n    // Read endlessly from the UnboundedReceiver and compute the fun score.\n    spawn_local(async move {\n        while let Some(joke) = rx.next().await {\n            sleep(ONE_SEC).await;\n            let score = joke.len() as i16;\n            fun_score_cb.emit(score);\n        }\n    });\n\n    tx\n}\n"
  },
  {
    "path": "examples/boids/Cargo.toml",
    "content": "[package]\nname = \"boids\"\nversion = \"0.1.0\"\nauthors = [\"motoki saito <stmtk13044032@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n[dependencies]\nanyhow.workspace = true\ngetrandom = { workspace = true }\nrand.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n\t\"HtmlInputElement\",\n]\n"
  },
  {
    "path": "examples/boids/README.md",
    "content": "# Boids Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fboids)](https://examples.yew.rs/boids)\n\nA version of [Boids](https://en.wikipedia.org/wiki/Boids) implemented in Yew.\n\nThis example doesn't make use of a [Canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API),\ninstead, each boid has its own element demonstrating the performance of Yew's virtual DOM.\n\n## Concepts\n\nThe example uses [`gloo::timers`](https://docs.rs/gloo-timers/latest/gloo_timers/) implementation of `setInterval` to drive the Yew game loop.\n\n## Improvements\n\n- Add the possibility to switch the behaviour from flocking to scattering by inverting the cohesion rule so that boids avoid each other.\n  This should also invert the color adaption to restore some variety.\n- Add keyboard shortcuts for the actions.\n- Make it possible to hide the settings panel entirely\n- Bigger boids should accelerate slower than smaller ones\n- Share settings by encoding them into the URL\n- Resize the boids when \"Spacing\" is changed.\n  The setting should then also be renamed to something like \"Size\".\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\nRUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' trunk serve --open\n```\n"
  },
  {
    "path": "examples/boids/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/boids/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Boids</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/boids/index.scss",
    "content": "$shade-0: #fff !default;\n$shade-1: #d7dcdf !default;\n$shade-10: #2c3e50 !default;\n$teal: #1abc9c !default;\n\nhtml,\nbody {\n  margin: 0;\n  padding: 0;\n\n  background: #1b1b1b;\n  color: whitesmoke;\n  font-family: \"Roboto\", sans-serif;\n  height: 100%;\n  overflow: hidden;\n}\n\n.title {\n  -webkit-text-fill-color: transparent;\n  -webkit-text-stroke-width: 3px;\n  -webkit-text-stroke-color: whitesmoke;\n\n  position: absolute;\n  margin: 0.2em 0 0 0;\n  width: 100%;\n\n  text-align: center;\n  font-size: 4em;\n  text-transform: full-width;\n}\n\n.simulation-window {\n  height: 100%;\n  width: 100%;\n}\n\n.panel {\n  position: absolute;\n  bottom: 0;\n  margin: 0 5em;\n  padding: 5em 0 1em 0;\n\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n\n  opacity: 20%;\n  transition: 500ms ease-in-out;\n\n  &:hover {\n    opacity: unset;\n  }\n\n  &__buttons {\n    margin-top: 1em;\n\n    & > * {\n      min-width: 10em;\n\n      &:not(:first-child) {\n        margin-left: 1em;\n      }\n    }\n  }\n}\n\nbutton {\n  color: $shade-0;\n  background: $shade-10;\n  padding: 0.5em 2em;\n\n  border: none;\n  border-radius: 1em;\n\n  transition: 250ms;\n\n  &:hover {\n    background: $teal;\n  }\n\n  &:active {\n    transform: scale(0.9);\n  }\n}\n\n.settings {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n\n  & > * {\n    flex-basis: 30%;\n  }\n}\n\n$slider-handle-color: $shade-10 !default;\n$slider-handle-color-hover: $teal !default;\n$slider-handle-size: 20px !default;\n\n$slider-track-color: $shade-1 !default;\n$slider-track-height: 10px !default;\n\n$slider-label-color: $shade-10 !default;\n$slider-label-width: 60px !default;\n\n.slider {\n  width: 20em;\n\n  &__label {\n    display: block;\n  }\n\n  &__input {\n    -webkit-appearance: none;\n    width: calc(100% - (#{$slider-label-width + 13px}));\n    height: $slider-track-height;\n    border-radius: 5px;\n    background: $slider-track-color;\n    outline: none;\n    padding: 0;\n    margin: 0;\n\n    // Range Handle\n    &::-webkit-slider-thumb {\n      appearance: none;\n      width: $slider-handle-size;\n      height: $slider-handle-size;\n      border-radius: 50%;\n      background: $slider-handle-color;\n      cursor: pointer;\n      transition: background 0.15s ease-in-out;\n\n      &:hover {\n        background: $slider-handle-color-hover;\n      }\n    }\n\n    &:active::-webkit-slider-thumb {\n      background: $slider-handle-color-hover;\n    }\n\n    &::-moz-range-thumb {\n      width: $slider-handle-size;\n      height: $slider-handle-size;\n      border: 0;\n      border-radius: 50%;\n      background: $slider-handle-color;\n      cursor: pointer;\n      transition: background 0.15s ease-in-out;\n\n      &:hover {\n        background: $slider-handle-color-hover;\n      }\n    }\n\n    &:active::-moz-range-thumb {\n      background: $slider-handle-color-hover;\n    }\n\n    // Focus state\n    &:focus {\n      &::-webkit-slider-thumb {\n        box-shadow: 0 0 0 3px $shade-0, 0 0 0 6px $teal;\n      }\n    }\n  }\n\n  &__value {\n    display: inline-block;\n    box-sizing: border-box;\n    position: relative;\n    width: $slider-label-width;\n    color: $shade-0;\n    line-height: 20px;\n    text-align: center;\n    border-radius: 3px;\n    background: $slider-label-color;\n    padding: 5px 10px;\n    margin-left: 8px;\n\n    &:after {\n      position: absolute;\n      top: 8px;\n      left: -7px;\n      width: 0;\n      height: 0;\n      border-top: 7px solid transparent;\n      border-right: 7px solid $slider-label-color;\n      border-bottom: 7px solid transparent;\n      content: \"\";\n    }\n  }\n}\n\n// Firefox Overrides\n::-moz-range-track {\n  background: $slider-track-color;\n  border: 0;\n}\n\ninput::-moz-focus-inner,\ninput::-moz-focus-outer {\n  border: 0;\n}\n"
  },
  {
    "path": "examples/boids/src/boid.rs",
    "content": "use std::fmt::Write;\nuse std::iter;\n\nuse rand::Rng;\nuse yew::{html, Html};\n\nuse crate::math::{self, Mean, Vector2D, WeightedMean};\nuse crate::settings::Settings;\nuse crate::simulation::SIZE;\n\n#[derive(Clone, Debug, PartialEq)]\npub struct Boid {\n    position: Vector2D,\n    velocity: Vector2D,\n    radius: f64,\n    hue: f64,\n}\n\nimpl Boid {\n    pub fn new_random(settings: &Settings) -> Self {\n        let mut rng = rand::rng();\n\n        let max_radius = settings.min_distance / 2.0;\n        let min_radius = max_radius / 6.0;\n        // by using the third power large boids become rarer\n        let radius = min_radius + rng.random::<f64>().powi(3) * (max_radius - min_radius);\n\n        Self {\n            position: Vector2D::new(rng.random::<f64>() * SIZE.x, rng.random::<f64>() * SIZE.y),\n            velocity: Vector2D::from_polar(rng.random::<f64>() * math::TAU, settings.max_speed),\n            radius,\n            hue: rng.random::<f64>() * math::TAU,\n        }\n    }\n\n    fn coherence(&self, boids: VisibleBoidIter, factor: f64) -> Vector2D {\n        Vector2D::weighted_mean(\n            boids.map(|other| (other.boid.position, other.boid.radius * other.boid.radius)),\n        )\n        .map(|mean| (mean - self.position) * factor)\n        .unwrap_or_default()\n    }\n\n    fn separation(&self, boids: VisibleBoidIter, settings: &Settings) -> Vector2D {\n        let accel = boids\n            .filter_map(|other| {\n                if other.distance > settings.min_distance {\n                    None\n                } else {\n                    Some(-other.offset)\n                }\n            })\n            .sum::<Vector2D>();\n        accel * settings.separation_factor\n    }\n\n    fn alignment(&self, boids: VisibleBoidIter, factor: f64) -> Vector2D {\n        Vector2D::mean(boids.map(|other| other.boid.velocity))\n            .map(|mean| (mean - self.velocity) * factor)\n            .unwrap_or_default()\n    }\n\n    fn adapt_color(&mut self, boids: VisibleBoidIter, factor: f64) {\n        let mean = f64::mean(boids.filter_map(|other| {\n            if other.boid.radius > self.radius {\n                Some(math::smallest_angle_between(self.hue, other.boid.hue))\n            } else {\n                None\n            }\n        }));\n        if let Some(avg_hue_offset) = mean {\n            self.hue += avg_hue_offset * factor;\n        }\n    }\n\n    fn keep_in_bounds(&mut self, settings: &Settings) {\n        let min = SIZE * settings.border_margin;\n        let max = SIZE - min;\n\n        let mut v = Vector2D::default();\n\n        let turn_speed = self.velocity.magnitude() * settings.turn_speed_ratio;\n        let pos = self.position;\n        if pos.x < min.x {\n            v.x += turn_speed;\n        }\n        if pos.x > max.x {\n            v.x -= turn_speed\n        }\n\n        if pos.y < min.y {\n            v.y += turn_speed;\n        }\n        if pos.y > max.y {\n            v.y -= turn_speed;\n        }\n\n        self.velocity += v;\n    }\n\n    fn update_velocity(&mut self, settings: &Settings, boids: VisibleBoidIter) {\n        let v = self.velocity\n            + self.coherence(boids.clone(), settings.cohesion_factor)\n            + self.separation(boids.clone(), settings)\n            + self.alignment(boids, settings.alignment_factor);\n        self.velocity = v.clamp_magnitude(settings.max_speed);\n    }\n\n    fn update(&mut self, settings: &Settings, boids: VisibleBoidIter) {\n        self.adapt_color(boids.clone(), settings.color_adapt_factor);\n        self.update_velocity(settings, boids);\n        self.keep_in_bounds(settings);\n        self.position += self.velocity;\n    }\n\n    pub fn update_all(settings: &Settings, boids: &mut [Self]) {\n        for i in 0..boids.len() {\n            let (before, after) = boids.split_at_mut(i);\n            let (boid, after) = after.split_first_mut().unwrap();\n            let visible_boids =\n                VisibleBoidIter::new(before, after, boid.position, settings.visible_range);\n\n            boid.update(settings, visible_boids);\n        }\n    }\n\n    pub fn render(&self) -> Html {\n        let color = format!(\"hsl({:.3}rad, 100%, 50%)\", self.hue);\n\n        let mut points = String::new();\n        for offset in iter_shape_points(self.radius, self.velocity.angle()) {\n            let Vector2D { x, y } = self.position + offset;\n\n            // Write to string will never fail.\n            let _ = write!(points, \"{x:.2},{y:.2} \");\n        }\n\n        html! { <polygon {points} fill={color} /> }\n    }\n}\n\nfn iter_shape_points(radius: f64, rotation: f64) -> impl Iterator<Item = Vector2D> {\n    const SHAPE: [(f64, f64); 3] = [\n        (0. * math::FRAC_TAU_3, 2.0),\n        (1. * math::FRAC_TAU_3, 1.0),\n        (2. * math::FRAC_TAU_3, 1.0),\n    ];\n    SHAPE\n        .iter()\n        .copied()\n        .map(move |(angle, radius_mul)| Vector2D::from_polar(angle + rotation, radius_mul * radius))\n}\n\n#[derive(Debug)]\nstruct VisibleBoid<'a> {\n    boid: &'a Boid,\n    offset: Vector2D,\n    distance: f64,\n}\n\n#[derive(Clone, Debug)]\nstruct VisibleBoidIter<'boid> {\n    // Pay no mind to this mess of a type.\n    // It's just `before` and `after` joined together.\n    it: iter::Chain<std::slice::Iter<'boid, Boid>, std::slice::Iter<'boid, Boid>>,\n    position: Vector2D,\n    visible_range: f64,\n}\nimpl<'boid> VisibleBoidIter<'boid> {\n    fn new(\n        before: &'boid [Boid],\n        after: &'boid [Boid],\n        position: Vector2D,\n        visible_range: f64,\n    ) -> Self {\n        Self {\n            it: before.iter().chain(after),\n            position,\n            visible_range,\n        }\n    }\n}\nimpl<'boid> Iterator for VisibleBoidIter<'boid> {\n    type Item = VisibleBoid<'boid>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let Self {\n            ref mut it,\n            position,\n            visible_range,\n        } = *self;\n\n        it.find_map(move |other| {\n            let offset = other.position - position;\n            let distance = offset.magnitude();\n\n            if distance > visible_range {\n                None\n            } else {\n                Some(VisibleBoid {\n                    boid: other,\n                    offset,\n                    distance,\n                })\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "examples/boids/src/main.rs",
    "content": "use settings::Settings;\nuse simulation::Simulation;\nuse slider::Slider;\nuse yew::html::Scope;\nuse yew::{html, Component, Context, Html};\n\nmod boid;\nmod math;\nmod settings;\nmod simulation;\nmod slider;\n\npub enum Msg {\n    ChangeSettings(Settings),\n    ResetSettings,\n    RestartSimulation,\n    TogglePause,\n}\n\npub struct App {\n    settings: Settings,\n    generation: usize,\n    paused: bool,\n}\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            settings: Settings::load(),\n            generation: 0,\n            paused: false,\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Msg) -> bool {\n        match msg {\n            Msg::ChangeSettings(settings) => {\n                self.settings = settings;\n                self.settings.store();\n                true\n            }\n            Msg::ResetSettings => {\n                self.settings = Settings::default();\n                Settings::remove();\n                true\n            }\n            Msg::RestartSimulation => {\n                self.generation = self.generation.wrapping_add(1);\n                true\n            }\n            Msg::TogglePause => {\n                self.paused = !self.paused;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let Self {\n            ref settings,\n            generation,\n            paused,\n            ..\n        } = *self;\n\n        html! {\n            <>\n                <h1 class=\"title\">{ \"Boids\" }</h1>\n                <Simulation settings={settings.clone()} {generation} {paused} />\n                { self.view_panel(ctx.link()) }\n            </>\n        }\n    }\n}\nimpl App {\n    fn view_panel(&self, link: &Scope<Self>) -> Html {\n        let pause_text = if self.paused { \"Resume\" } else { \"Pause\" };\n        html! {\n            <div class=\"panel\">\n                { self.view_settings(link) }\n                <div class=\"panel__buttons\">\n                    <button onclick={link.callback(|_| Msg::TogglePause)}>{ pause_text }</button>\n                    <button onclick={link.callback(|_| Msg::ResetSettings)}>{ \"Use Defaults\" }</button>\n                    <button onclick={link.callback(|_| Msg::RestartSimulation)}>{ \"Restart\" }</button>\n                </div>\n            </div>\n        }\n    }\n\n    fn view_settings(&self, link: &Scope<Self>) -> Html {\n        let Self { settings, .. } = self;\n\n        // This helper macro creates a callback which applies the new value to the current settings\n        // and sends `Msg::ChangeSettings`. Thanks to this, we don't need to have\n        // \"ChangeBoids\", \"ChangeCohesion\", etc. messages, but it comes at the cost of\n        // cloning the `Settings` struct each time.\n        macro_rules! settings_callback {\n            ($link:expr, $settings:ident; $key:ident as $ty:ty) => {{\n                let settings = $settings.clone();\n                $link.callback(move |value| {\n                    let mut settings = settings.clone();\n                    settings.$key = value as $ty;\n                    Msg::ChangeSettings(settings)\n                })\n            }};\n            ($link:expr, $settings:ident; $key:ident) => {\n                settings_callback!($link, $settings; $key as f64)\n            }\n        }\n\n        html! {\n            <div class=\"settings\">\n                <Slider label=\"Number of Boids\"\n                    min=1.0 max=600.0\n                    onchange={settings_callback!(link, settings; boids as usize)}\n                    value={settings.boids as f64}\n                />\n                <Slider label=\"View Distance\"\n                    max=500.0 step=10.0\n                    onchange={settings_callback!(link, settings; visible_range)}\n                    value={settings.visible_range}\n                />\n                <Slider label=\"Spacing\"\n                    max=100.0\n                    onchange={settings_callback!(link, settings; min_distance)}\n                    value={settings.min_distance}\n                />\n                <Slider label=\"Max Speed\"\n                    max=50.0\n                    onchange={settings_callback!(link, settings; max_speed)}\n                    value={settings.max_speed}\n                />\n                <Slider label=\"Cohesion\"\n                    max=0.5 percentage=true\n                    onchange={settings_callback!(link, settings; cohesion_factor)}\n                    value={settings.cohesion_factor}\n                />\n                <Slider label=\"Separation\"\n                    max=1.0 percentage=true\n                    onchange={settings_callback!(link, settings; separation_factor)}\n                    value={settings.separation_factor}\n                />\n                <Slider label=\"Alignment\"\n                    max=0.5 percentage=true\n                    onchange={settings_callback!(link, settings; alignment_factor)}\n                    value={settings.alignment_factor}\n                />\n                <Slider label=\"Turn Speed\"\n                    max=1.5 percentage=true\n                    onchange={settings_callback!(link, settings; turn_speed_ratio)}\n                    value={settings.turn_speed_ratio}\n                />\n                <Slider label=\"Color Adaption\"\n                    max=1.5 percentage=true\n                    onchange={settings_callback!(link, settings; color_adapt_factor)}\n                    value={settings.color_adapt_factor}\n                />\n            </div>\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/boids/src/math.rs",
    "content": "use std::f64::consts::{FRAC_PI_3, PI};\nuse std::iter::Sum;\nuse std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};\n\n// at the time of writing the TAU constant is still unstable\npub const TAU: f64 = 2.0 * PI;\npub const FRAC_TAU_3: f64 = 2.0 * FRAC_PI_3;\n\n/// Get the smaller signed angle from `source` to `target`.\n/// The result is in the range `[-PI, PI)`.\npub fn smallest_angle_between(source: f64, target: f64) -> f64 {\n    let d = target - source;\n    (d + PI).rem_euclid(TAU) - PI\n}\n\n#[derive(Clone, Copy, Debug, Default, PartialEq)]\npub struct Vector2D {\n    pub x: f64,\n    pub y: f64,\n}\nimpl Vector2D {\n    pub const fn new(x: f64, y: f64) -> Self {\n        Self { x, y }\n    }\n\n    pub fn from_polar(angle: f64, radius: f64) -> Self {\n        let (sin, cos) = angle.sin_cos();\n        Self::new(radius * cos, radius * sin)\n    }\n\n    pub fn magnitude_squared(self) -> f64 {\n        self.x * self.x + self.y * self.y\n    }\n\n    pub fn magnitude(self) -> f64 {\n        self.magnitude_squared().sqrt()\n    }\n\n    pub fn clamp_magnitude(self, max: f64) -> Self {\n        let mag = self.magnitude();\n        if mag > max {\n            self / mag * max\n        } else {\n            self\n        }\n    }\n\n    /// Positive angles measured counter-clockwise from positive x axis.\n    pub fn angle(self) -> f64 {\n        self.y.atan2(self.x)\n    }\n}\n\nimpl Neg for Vector2D {\n    type Output = Self;\n\n    fn neg(self) -> Self::Output {\n        Self::new(-self.x, -self.y)\n    }\n}\n\nimpl AddAssign for Vector2D {\n    fn add_assign(&mut self, other: Self) {\n        self.x += other.x;\n        self.y += other.y;\n    }\n}\nimpl Add for Vector2D {\n    type Output = Self;\n\n    fn add(mut self, rhs: Self) -> Self::Output {\n        self += rhs;\n        self\n    }\n}\n\nimpl SubAssign for Vector2D {\n    fn sub_assign(&mut self, other: Self) {\n        self.x -= other.x;\n        self.y -= other.y;\n    }\n}\nimpl Sub for Vector2D {\n    type Output = Self;\n\n    fn sub(mut self, rhs: Self) -> Self::Output {\n        self -= rhs;\n        self\n    }\n}\n\nimpl MulAssign<f64> for Vector2D {\n    fn mul_assign(&mut self, scalar: f64) {\n        self.x *= scalar;\n        self.y *= scalar;\n    }\n}\nimpl Mul<f64> for Vector2D {\n    type Output = Self;\n\n    fn mul(mut self, rhs: f64) -> Self::Output {\n        self *= rhs;\n        self\n    }\n}\n\nimpl DivAssign<f64> for Vector2D {\n    fn div_assign(&mut self, scalar: f64) {\n        self.x /= scalar;\n        self.y /= scalar;\n    }\n}\nimpl Div<f64> for Vector2D {\n    type Output = Self;\n\n    fn div(mut self, rhs: f64) -> Self::Output {\n        self /= rhs;\n        self\n    }\n}\n\nimpl Sum for Vector2D {\n    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {\n        iter.fold(Self::default(), |sum, v| sum + v)\n    }\n}\n\npub trait WeightedMean<T = Self>: Sized {\n    fn weighted_mean(it: impl Iterator<Item = (T, f64)>) -> Option<Self>;\n}\n\nimpl<T> WeightedMean for T\nwhere\n    T: AddAssign + Mul<f64, Output = T> + Div<f64, Output = T> + Copy + Default,\n{\n    fn weighted_mean(it: impl Iterator<Item = (T, f64)>) -> Option<T> {\n        let (sum, total_weight) = it.fold(\n            (T::default(), 0.0),\n            |(mut sum, total_weight), (value, weight)| {\n                sum += value * weight;\n                (sum, total_weight + weight)\n            },\n        );\n        if total_weight.is_normal() {\n            Some(sum / total_weight)\n        } else {\n            None\n        }\n    }\n}\n\npub trait Mean<T = Self>: Sized {\n    fn mean(it: impl Iterator<Item = T>) -> Option<Self>;\n}\n\nimpl<T> Mean for T\nwhere\n    T: AddAssign + Sub<Output = T> + Div<f64, Output = T> + Copy + Default,\n{\n    fn mean(it: impl Iterator<Item = T>) -> Option<T> {\n        let (avg, count) = it.fold((T::default(), 0.0), |(mut avg, mut count), value| {\n            count += 1.0;\n            avg += (value - avg) / count;\n            (avg, count)\n        });\n        if count.is_normal() {\n            Some(avg)\n        } else {\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "examples/boids/src/settings.rs",
    "content": "use gloo::storage::{LocalStorage, Storage};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]\npub struct Settings {\n    /// amount of boids\n    pub boids: usize,\n    // time between each simulation tick\n    pub tick_interval_ms: u64,\n    /// view distance of a boid\n    pub visible_range: f64,\n    /// distance boids try to keep between each other\n    pub min_distance: f64,\n    /// max speed\n    pub max_speed: f64,\n    /// force multiplier for pulling boids together\n    pub cohesion_factor: f64,\n    /// force multiplier for separating boids\n    pub separation_factor: f64,\n    /// force multiplier for matching velocity of other boids\n    pub alignment_factor: f64,\n    /// controls turn speed to avoid leaving boundary\n    pub turn_speed_ratio: f64,\n    /// percentage of the size to the boundary at which a boid starts turning away\n    pub border_margin: f64,\n    /// factor for adapting the average color of the swarm\n    pub color_adapt_factor: f64,\n}\nimpl Settings {\n    const KEY: &'static str = \"yew.boids.settings\";\n\n    pub fn load() -> Self {\n        LocalStorage::get(Self::KEY).unwrap_or_default()\n    }\n\n    pub fn remove() {\n        LocalStorage::delete(Self::KEY);\n    }\n\n    pub fn store(&self) {\n        let _ = LocalStorage::set(Self::KEY, self);\n    }\n}\nimpl Default for Settings {\n    fn default() -> Self {\n        Self {\n            boids: 300,\n            tick_interval_ms: 50,\n            visible_range: 80.0,\n            min_distance: 15.0,\n            max_speed: 20.0,\n            alignment_factor: 0.15,\n            cohesion_factor: 0.05,\n            separation_factor: 0.6,\n            turn_speed_ratio: 0.25,\n            border_margin: 0.1,\n            color_adapt_factor: 0.05,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/boids/src/simulation.rs",
    "content": "use gloo::timers::callback::Interval;\nuse yew::{html, Component, Context, Html, Properties};\n\nuse crate::boid::Boid;\nuse crate::math::Vector2D;\nuse crate::settings::Settings;\n\npub const SIZE: Vector2D = Vector2D::new(1600.0, 1000.0);\n\n#[derive(Debug)]\npub enum Msg {\n    Tick,\n}\n\n#[derive(Clone, Debug, PartialEq, Properties)]\npub struct Props {\n    pub settings: Settings,\n    #[prop_or_default]\n    pub generation: usize,\n    #[prop_or_default]\n    pub paused: bool,\n}\n\n#[derive(Debug)]\npub struct Simulation {\n    boids: Vec<Boid>,\n    interval: Interval,\n    generation: usize,\n}\nimpl Component for Simulation {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let settings = ctx.props().settings.clone();\n        let boids = (0..settings.boids)\n            .map(|_| Boid::new_random(&settings))\n            .collect();\n\n        let interval = {\n            let link = ctx.link().clone();\n            Interval::new(settings.tick_interval_ms as u32, move || {\n                link.send_message(Msg::Tick)\n            })\n        };\n\n        let generation = ctx.props().generation;\n        Self {\n            boids,\n            interval,\n            generation,\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Tick => {\n                let Props {\n                    ref settings,\n                    paused,\n                    ..\n                } = *ctx.props();\n\n                if paused {\n                    false\n                } else {\n                    Boid::update_all(settings, &mut self.boids);\n                    true\n                }\n            }\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {\n        let props = ctx.props();\n        let should_reset =\n            old_props.settings != props.settings || self.generation != props.generation;\n        self.generation = props.generation;\n        if should_reset {\n            self.boids.clear();\n\n            let settings = &props.settings;\n            self.boids\n                .resize_with(settings.boids, || Boid::new_random(settings));\n\n            // as soon as the previous task is dropped it is cancelled.\n            // We don't need to worry about manually stopping it.\n            self.interval = {\n                let link = ctx.link().clone();\n                Interval::new(settings.tick_interval_ms as u32, move || {\n                    link.send_message(Msg::Tick)\n                })\n            };\n\n            true\n        } else {\n            false\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let view_box = format!(\"0 0 {} {}\", SIZE.x, SIZE.y);\n\n        html! {\n            <svg class=\"simulation-window\" viewBox={view_box}>\n                { for self.boids.iter().map(Boid::render) }\n            </svg>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/boids/src/slider.rs",
    "content": "use std::cell::Cell;\n\nuse web_sys::HtmlInputElement;\nuse yew::events::InputEvent;\nuse yew::{html, Callback, Component, Context, Html, Properties, TargetCast};\n\nthread_local! {\n    static SLIDER_ID: Cell<usize> = Cell::default();\n}\nfn next_slider_id() -> usize {\n    SLIDER_ID.with(|cell| cell.replace(cell.get() + 1))\n}\n\n#[derive(Clone, Debug, PartialEq, Properties)]\npub struct Props {\n    pub label: &'static str,\n    pub value: f64,\n    pub onchange: Callback<f64>,\n    #[prop_or_default]\n    pub precision: Option<usize>,\n    #[prop_or_default]\n    pub percentage: bool,\n    #[prop_or_default]\n    pub min: f64,\n    pub max: f64,\n    #[prop_or_default]\n    pub step: Option<f64>,\n}\n\npub struct Slider {\n    id: usize,\n}\nimpl Component for Slider {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            id: next_slider_id(),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        unimplemented!()\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let Props {\n            label,\n            value,\n            ref onchange,\n            precision,\n            percentage,\n            min,\n            max,\n            step,\n        } = *ctx.props();\n\n        let precision = precision.unwrap_or_else(|| usize::from(percentage));\n\n        let display_value = if percentage {\n            format!(\"{:.p$}%\", 100.0 * value, p = precision)\n        } else {\n            format!(\"{value:.precision$}\")\n        };\n\n        let id = format!(\"slider-{}\", self.id);\n        let step = step.unwrap_or_else(|| {\n            let p = if percentage { precision + 2 } else { precision };\n            10f64.powi(-(p as i32))\n        });\n\n        let oninput = onchange.reform(|e: InputEvent| {\n            let input: HtmlInputElement = e.target_unchecked_into();\n            input.value_as_number()\n        });\n\n        html! {\n            <div class=\"slider\">\n                <label for={id.clone()} class=\"slider__label\">{ label }</label>\n                <input type=\"range\"\n                    value={value.to_string()}\n                    {id}\n                    class=\"slider__input\"\n                    min={min.to_string()} max={max.to_string()} step={step.to_string()}\n                    {oninput}\n                />\n                <span class=\"slider__value\">{ display_value }</span>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_child_to_parent/Cargo.toml",
    "content": "[package]\nname = \"communication_child_to_parent\"\nversion = \"0.0.1\"\nauthors = [\"Marcel Ibes <mibes@mibesco.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/communication_child_to_parent/README.md",
    "content": "# Child-to-Parent Example\n\nA simple example of updating a parent from two children using a callback mechanism.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```\n"
  },
  {
    "path": "examples/communication_child_to_parent/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/communication_child_to_parent/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Child-to-Parent Communication</title>\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body class=\"page\"></body>\n</html>\n"
  },
  {
    "path": "examples/communication_child_to_parent/index.scss",
    "content": ".page {\n    min-height: 100vh;\n    min-width: 100vw;\n\n    line-height: 1.5;\n    tab-size: 4;\n    font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n    font-feature-settings: normal;\n\n    margin: 0;\n    line-height: inherit;\n}\n\n.parent {\n    color: rgb(244 244 245);\n    background-color: rgb(24 24 27);\n\n    justify-content: center;\n    align-items: center;\n    flex-direction: column;\n    display: flex;\n\n    min-height: 100vh;\n    min-width: 100vw;\n}\n\n.title {\n    font-size: 2.25rem;\n    line-height: 2.5rem;\n    font-weight: inherit;\n\n    margin: 0;\n    margin-bottom: 2rem;\n}\n\n// Bodies\n\n.parent-body, .child-body {\n    border-width: 4px;\n    border-radius: 1rem;\n\n    border-style: solid;\n}\n\n.parent-body {\n    border-color: rgb(22 163 74);\n}\n\n.child-body {\n    border-color: rgb(249 115 22);\n\n    flex-grow: 1;\n}\n\n// Tags\n\n.parent-tag, .child-tag {\n    font-weight: 500;\n\n    padding-bottom: 0.25rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    border-top-left-radius: 0.25rem;\n    border-top-right-radius: 0.25rem;\n\n    line-height: 24px;\n}\n\n.parent-tag {\n    background-color: rgb(22 163 74);\n}\n\n.child-tag {\n    background-color: rgb(249 115 22);\n}\n\n// Content\n\n.parent-content {\n    padding-top: 0.75rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    flex-direction: column;\n    display: flex;\n}\n\n.parent-content > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.parent-content > span > span {\n    font-weight: 700;\n}\n\n.parent-content > span:nth-child(2) {\n    margin-top: 0.75rem;\n    margin-bottom: 0.75rem;\n}\n\n.parent-content > div {\n    column-gap: 1.25rem;\n    display: flex;\n\n    margin-top: 0.75rem;\n}\n\n.child-content {\n    padding-top: 1.25rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    justify-content: space-between;\n    align-items: center;\n    display: flex;\n}\n\n.child-content > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.child-content > button {\n    font-weight: 500;\n    font-size: 1.125rem;\n    line-height: 1.75rem;\n    text-transform: none;\n    font-family: inherit;\n\n    padding-top: 0.25rem;\n    padding-bottom: 0.5rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    background-color: rgb(249 115 22);\n\n    border-radius: 0.75rem;\n    border-width: 0;\n    color: rgb(244 244 245);\n    cursor: pointer;\n}\n\n.child-content > button:hover {\n    background-color: rgb(194 65 12);\n}"
  },
  {
    "path": "examples/communication_child_to_parent/src/child.rs",
    "content": "use super::*;\n\n/// The `Child` component is the child of the `Parent` component, and will send updates to the\n/// parent using a Callback.\npub struct Child;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ChildProps {\n    pub name: AttrValue,\n    pub on_clicked: Callback<AttrValue>,\n}\n\nimpl Component for Child {\n    type Message = ();\n    type Properties = ChildProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {}\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let name = format!(\"I'm {}.\", ctx.props().name);\n        let my_name = ctx.props().name.clone();\n\n        // Here we emit the callback to the parent component, whenever the button is clicked.\n        let onclick = ctx.props().on_clicked.reform(move |_| my_name.clone());\n\n        html! {\n            <div class=\"child-body\">\n                <div class=\"child-tag\">\n                    <span>{ \"Child\" }</span>\n                </div>\n                <div class=\"child-content\">\n                    <span>{ name }</span>\n                    <button {onclick}>{\"Click\"}</button>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_child_to_parent/src/main.rs",
    "content": "use child::Child;\nuse parent::Parent;\nuse yew::{html, AttrValue, Callback, Component, Context, Html, Properties};\n\nmod child;\nmod parent;\n\nfn main() {\n    yew::Renderer::<Parent>::new().render();\n}\n"
  },
  {
    "path": "examples/communication_child_to_parent/src/parent.rs",
    "content": "use super::*;\n\npub enum Msg {\n    ButtonClick(AttrValue),\n}\n\n/// The `Parent` component holds some state that is updated when its children are clicked\npub struct Parent {\n    /// The total number of clicks received\n    total_clicks: u32,\n    /// The name of the child that was last clicked\n    last_updated: Option<AttrValue>,\n}\nimpl Component for Parent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            total_clicks: 0,\n            last_updated: None,\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ButtonClick(child_name) => {\n                // Keep track of the name of the child that was clicked\n                self.last_updated = Some(child_name);\n\n                // Increment the total number of clicks\n                self.total_clicks += 1;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let last_updated_msg = if let Some(last_updated) = self.last_updated.as_ref() {\n            format!(\"The last child you clicked was {last_updated}.\")\n        } else {\n            \"Waiting for you to click a child...\".to_string()\n        };\n\n        let on_clicked = ctx.link().callback(Msg::ButtonClick);\n        html! {\n            <div class=\"parent\">\n                <div>\n                    <h2 class=\"title\">{ \"Child-to-Parent Communication Example\" }</h2>\n                    <div class=\"parent-body\">\n                        <div class=\"parent-tag\">\n                            <span>{ \"Parent\" }</span>\n                        </div>\n                        <div class=\"parent-content\">\n                            <span>{ \"My children have been clicked \" }<span>{ self.total_clicks }</span>{ \" times.\" }</span>\n                            <span>{ last_updated_msg }</span>\n                            <div>\n                                <Child name=\"Alice\" on_clicked={on_clicked.clone()} />\n                                <Child name=\"Bob\" {on_clicked} />\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/Cargo.toml",
    "content": "[package]\nname = \"communication_grandchild_with_grandparent\"\nversion = \"0.0.1\"\nauthors = [\"Marcel Ibes <mibes@mibesco.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/README.md",
    "content": "# Grandchild-with-Grandparent Example\n\nA simple example of updating a grandparent component from two grandchildren using a callback passed down using the context API.\nThe grandchildren themselves also update whenever the grandparent updates the shared state.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Grandchild-to-Grandparent Communication</title>\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body class=\"page\"></body>\n</html>\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/index.scss",
    "content": ".page {\n    min-height: 100vh;\n    min-width: 100vw;\n\n    line-height: 1.5;\n    tab-size: 4;\n    font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n    font-feature-settings: normal;\n\n    margin: 0;\n    line-height: inherit;\n}\n\n.grandparent {\n    color: rgb(244 244 245);\n    background-color: rgb(24 24 27);\n\n    justify-content: center;\n    align-items: center;\n    flex-direction: column;\n    display: flex;\n\n    min-height: 100vh;\n    min-width: 100vw;\n}\n\n.title {\n    font-size: 2.25rem;\n    line-height: 2.5rem;\n    font-weight: inherit;\n\n    margin: 0;\n    margin-bottom: 2rem;\n}\n\n// Bodies\n\n.grandparent-body, .parent-body, .child-body {\n    border-width: 4px;\n    border-radius: 1rem;\n\n    border-style: solid;\n}\n\n.grandparent-body {\n    border-color: rgb(22 163 74);\n}\n\n.parent-body, .child-body {\n    flex-grow: 1;\n}\n\n.parent-body {\n    border-color: rgb(249 115 22);\n}\n\n.child-body {\n    border-color: rgb(147 51 234);\n\n    margin-top: 0.5rem;\n}\n\n.child-body > div:nth-child(2) {\n    padding-top: 0.75rem;\n    padding-bottom: 0.75rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n}\n\n.child-body > div:nth-child(2) > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.child-body > div:nth-child(2) > span > span {\n    font-weight: 700;\n}\n\n// Tags\n\n.grandparent-tag, .parent-tag, .child-tag {\n    font-weight: 500;\n\n    padding-bottom: 0.25rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    border-top-left-radius: 0.25rem;\n    border-top-right-radius: 0.25rem;\n\n    line-height: 24px;\n}\n\n.grandparent-tag {\n    background-color: rgb(22 163 74);\n}\n\n.parent-tag {\n    background-color: rgb(249 115 22);\n}\n\n.child-tag {\n    background-color: rgb(147 51 234);\n}\n\n// Content\n\n.grandparent-content {\n    padding-top: 0.75rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    flex-direction: column;\n    display: flex;\n}\n\n.grandparent-content > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.grandparent-content > span:nth-child(2) {\n    margin-top: 0.75rem;\n    margin-bottom: 0.75rem;\n}\n\n.grandparent-content > span > span {\n    font-weight: 700;\n}\n\n.parent-content {\n    padding-top: 0.75rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    column-gap: 1.25rem;\n    display: flex;\n}\n\n.child-content {\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    justify-content: space-between;\n    align-items: center;\n    display: flex;\n}\n\n.child-content > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.child-content > button {\n    font-weight: 500;\n    font-size: 1.125rem;\n    line-height: 1.75rem;\n    text-transform: none;\n    font-family: inherit;\n\n    padding-top: 0.25rem;\n    padding-bottom: 0.5rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    background-color: rgb(147 51 234);\n\n    border-radius: 0.75rem;\n    border-width: 0;\n    color: rgb(244 244 245);\n    cursor: pointer;\n}\n\n.child-content > button:hover {\n    background-color: rgb(107 33 168);\n}"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/src/child.rs",
    "content": "use super::*;\n\n/// The `Child` component is the child of the `Parent` component, and will send and receive updates\n/// to/from the grandparent using the context.\npub struct Child {\n    state: Rc<AppState>,\n    _listener: ContextHandle<Rc<AppState>>,\n}\n\npub enum ChildMsg {\n    ContextChanged(Rc<AppState>),\n}\n\n#[derive(Clone, Eq, PartialEq, Properties)]\npub struct ChildProps {\n    pub name: AttrValue,\n}\n\nimpl Component for Child {\n    type Message = ChildMsg;\n    type Properties = ChildProps;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        // Here we fetch the shared state from the context. For a demonstration on the use of\n        // context in a functional component, have a look at the `examples/contexts` code.\n        let (state, _listener) = ctx\n            .link()\n            .context::<Rc<AppState>>(ctx.link().callback(ChildMsg::ContextChanged))\n            .expect(\"context to be set\");\n\n        Self { state, _listener }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            ChildMsg::ContextChanged(state) => {\n                self.state = state;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let my_name = ctx.props().name.clone();\n        let name = format!(\"I'm {my_name}.\");\n\n        // Here we emit the callback to the grandparent component, whenever the button is clicked.\n        let onclick = self.state.child_clicked.reform(move |_| my_name.clone());\n\n        html! {\n            <div class=\"child-body\">\n                <div class=\"child-tag\">\n                    <span>{ \"Child\" }</span>\n                </div>\n                <div>\n                    <span>{ \"We've been clicked \" }<span>{ self.state.total_clicks }</span>{ \" times.\" }</span>\n                </div>\n                <div class=\"child-content\">\n                    <span>{ name }</span>\n                    <button {onclick}>{\"Click\"}</button>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/src/grandparent.rs",
    "content": "use super::*;\n\npub enum Msg {\n    ButtonClick(AttrValue),\n}\n\n/// Our top-level (grandparent) component that holds a reference to the shared state.\npub struct GrandParent {\n    state: Rc<AppState>,\n}\nimpl Component for GrandParent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let child_clicked = ctx.link().callback(Msg::ButtonClick);\n        let state = Rc::new(AppState {\n            total_clicks: 0,\n            child_clicked,\n            last_clicked: None,\n        });\n        Self { state }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ButtonClick(child_name) => {\n                // Update the shared state\n                let shared_state = Rc::make_mut(&mut self.state);\n                shared_state.total_clicks += 1;\n                shared_state.last_clicked = Some(child_name);\n                true\n            }\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let app_state = self.state.clone();\n\n        let detail_msg = if let Some(last_clicked) = &self.state.last_clicked {\n            format!(\"The last child you clicked was {last_clicked}.\")\n        } else {\n            \"Waiting for you to click a grandchild...\".to_string()\n        };\n\n        html! {\n            <ContextProvider<Rc<AppState>> context={app_state}>\n                <div class=\"grandparent\">\n                    <div>\n                        <h2 class=\"title\">{ \"Grandchild-with-Grandparent Communication Example\" }</h2>\n                        <div class=\"grandparent-body\">\n                            <div class=\"grandparent-tag\">\n                                <span>{ \"Grandparent\" }</span>\n                            </div>\n                            <div class=\"grandparent-content\">\n                                <span>{ \"My grandchildren have been clicked \" }<span>{ self.state.total_clicks }</span>{ \" times.\" }</span>\n                                <span>{detail_msg}</span>\n                                <Parent />\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </ContextProvider<Rc<AppState>>>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/src/main.rs",
    "content": "use std::rc::Rc;\n\nuse child::Child;\nuse grandparent::GrandParent;\nuse parent::Parent;\n\nmod child;\nmod grandparent;\nmod parent;\n\nuse yew::{\n    function_component, html, AttrValue, Callback, Component, Context, ContextHandle,\n    ContextProvider, Html, Properties,\n};\n\n/// This is the shared state between the parent and child components.\n#[derive(Clone, PartialEq)]\npub struct AppState {\n    /// Total number of clicks received.\n    total_clicks: u32,\n    /// Callback used when a child is clicked. The AttrValue is the name of the child that was\n    /// clicked.\n    child_clicked: Callback<AttrValue>,\n    /// The name of the child that was last clicked.\n    last_clicked: Option<AttrValue>,\n}\n\nfn main() {\n    yew::Renderer::<GrandParent>::new().render();\n}\n"
  },
  {
    "path": "examples/communication_grandchild_with_grandparent/src/parent.rs",
    "content": "use super::*;\n\n/// The `Parent` component is the parent of the `Child` component. It has no logic, and is here to\n/// show there is no direct relation between grandchild and grandparent.\n#[function_component]\npub fn Parent() -> Html {\n    html! {\n        <div class=\"parent-body\">\n            <div class=\"parent-tag\">\n                <span>{ \"Parent\" }</span>\n            </div>\n            <div class=\"parent-content\">\n                <Child name=\"Alice\" />\n                <Child name=\"Bob\" />\n            </div>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/Cargo.toml",
    "content": "[package]\nname = \"communication_grandparent_to_grandchild\"\nversion = \"0.0.1\"\nauthors = [\"Marcel Ibes <mibes@mibesco.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/README.md",
    "content": "# Grandparent-to-Grandchild Example\n\nA simple example of updating a grandchild component from a grandparent using a shared state through the ContextProvider.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Grandparent-to-Grandchild Communication</title>\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body class=\"page\"></body>\n</html>\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/index.scss",
    "content": ".page {\n    min-height: 100vh;\n    min-width: 100vw;\n\n    line-height: 1.5;\n    tab-size: 4;\n    font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n    font-feature-settings: normal;\n\n    margin: 0;\n    line-height: inherit;\n}\n\n.grandparent {\n    color: rgb(244 244 245);\n    background-color: rgb(24 24 27);\n\n    justify-content: center;\n    align-items: center;\n    flex-direction: column;\n    display: flex;\n\n    min-height: 100vh;\n    min-width: 100vw;\n}\n\n.title {\n    font-size: 2.25rem;\n    line-height: 2.5rem;\n    font-weight: inherit;\n\n    margin: 0;\n    margin-bottom: 2rem;\n}\n\n// Bodies\n\n.grandparent-body, .parent-body, .child-body {\n    border-width: 4px;\n    border-radius: 1rem;\n\n    border-style: solid;\n}\n\n.grandparent-body {\n    border-color: rgb(22 163 74);\n}\n\n.parent-body, .child-body {\n    flex-grow: 1;\n}\n\n.parent-body {\n    border-color: rgb(249 115 22);\n}\n\n.child-body {\n    border-color: rgb(147 51 234);\n\n    margin-top: 0.5rem;\n}\n\n.child-body > div:nth-child(2) {\n    padding-top: 0.75rem;\n    padding-bottom: 0.75rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n}\n\n.child-body > div:nth-child(2) > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.child-body > div:nth-child(2) > span > span {\n    font-weight: 700;\n}\n\n// Tags\n\n.grandparent-tag, .parent-tag, .child-tag {\n    font-weight: 500;\n\n    padding-bottom: 0.25rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    border-top-left-radius: 0.25rem;\n    border-top-right-radius: 0.25rem;\n\n    line-height: 24px;\n}\n\n.grandparent-tag {\n    background-color: rgb(22 163 74);\n}\n\n.parent-tag {\n    background-color: rgb(249 115 22);\n}\n\n.child-tag {\n    background-color: rgb(147 51 234);\n}\n\n// Content\n\n.grandparent-content {\n    padding-top: 1.25rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    flex-direction: column;\n    display: flex;\n}\n\n.grandparent-content > button {\n    font-weight: 500;\n    font-size: 1.125rem;\n    line-height: 1.75rem;\n    text-transform: none;\n    font-family: inherit;\n\n    padding-top: 0.25rem;\n    padding-bottom: 0.5rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    margin-bottom: 1.25rem;\n\n    background-color: rgb(22 163 74);\n\n    border-radius: 0.75rem;\n    border-width: 0;\n    color: rgb(244 244 245);\n    cursor: pointer;\n}\n\n.grandparent-content > button:hover {\n    background-color: rgb(22 101 52);\n}\n\n.parent-content {\n    padding-top: 0.75rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    column-gap: 1.25rem;\n    display: flex;\n}\n\n.child-content {\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    justify-content: space-between;\n    align-items: center;\n    display: flex;\n}\n\n.child-content > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/src/child.rs",
    "content": "use super::*;\n\n/// The `Child` component is the child of the `Parent` component, and will receive updates from the\n/// grandparent using the context.\npub struct Child {\n    state: Rc<AppState>,\n    _listener: ContextHandle<Rc<AppState>>,\n}\n\npub enum ChildMsg {\n    ContextChanged(Rc<AppState>),\n}\n\nimpl Component for Child {\n    type Message = ChildMsg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        // Here we fetch the shared state from the context. For a demonstration on the use of\n        // context in a functional component, have a look at the `examples/contexts` code.\n        let (state, _listener) = ctx\n            .link()\n            .context::<Rc<AppState>>(ctx.link().callback(ChildMsg::ContextChanged))\n            .expect(\"context to be set\");\n\n        Self { state, _listener }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            ChildMsg::ContextChanged(state) => {\n                self.state = state;\n                true\n            }\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n\n            <div class=\"child-body\">\n                <div class=\"child-tag\">\n                    <span>{ \"Child\" }</span>\n                </div>\n                <div class=\"child-content\">\n                    <span>{ \"My grandparent has been clicked \" }<span>{ self.state.total_clicks }</span>{ \" times.\" }</span>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/src/grandparent.rs",
    "content": "use super::*;\n\n/// Our top-level (grandparent) component that holds a reference to the shared state.\npub struct GrandParent {\n    state: Rc<AppState>,\n}\n\npub enum Msg {\n    ButtonClick,\n}\n\nimpl Component for GrandParent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        let state = Rc::new(AppState { total_clicks: 0 });\n        Self { state }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ButtonClick => {\n                Rc::make_mut(&mut self.state).total_clicks += 1;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::ButtonClick);\n        let app_state = self.state.clone();\n\n        html! {\n            <ContextProvider<Rc<AppState>> context={app_state}>\n                <div class=\"grandparent\">\n                    <div>\n                        <h2 class=\"title\">{ \"Grandparent-to-Grandchild Communication Example\" }</h2>\n\n                        <div class=\"grandparent-body\">\n                            <div class=\"grandparent-tag\">\n                                <span>{ \"Grandparent\" }</span>\n                            </div>\n                            <div class=\"grandparent-content\">\n                                <button {onclick}>{\"Click\"}</button>\n                                <Parent />\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </ContextProvider<Rc<AppState>>>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/src/main.rs",
    "content": "use std::rc::Rc;\n\nuse child::Child;\nuse grandparent::GrandParent;\nuse parent::Parent;\n\nmod child;\nmod grandparent;\nmod parent;\n\nuse yew::{function_component, html, Component, Context, ContextHandle, ContextProvider, Html};\n\n/// This is the shared state between the parent and child components.\n#[derive(Clone, Eq, PartialEq)]\npub struct AppState {\n    /// The total number of clicks received.\n    total_clicks: u32,\n}\n\nfn main() {\n    yew::Renderer::<GrandParent>::new().render();\n}\n"
  },
  {
    "path": "examples/communication_grandparent_to_grandchild/src/parent.rs",
    "content": "use super::*;\n\n/// The `Parent` component is the parent of the `Child` component. It has no logic, and is here to\n/// show there is no direct relation between grandchild and grandparent.\n#[function_component]\npub fn Parent() -> Html {\n    html! {\n        <div class=\"parent-body\">\n            <div class=\"parent-tag\">\n                <span>{ \"Parent\" }</span>\n            </div>\n            <div class=\"parent-content\">\n                <Child />\n            </div>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/communication_parent_to_child/Cargo.toml",
    "content": "[package]\nname = \"communication_parent_to_child\"\nversion = \"0.0.1\"\nauthors = [\"Marcel Ibes <mibes@mibesco.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/communication_parent_to_child/README.md",
    "content": "# Parent-to-Child Example\n\nA simple example of updating a child from a parent using properties\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/communication_parent_to_child/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/communication_parent_to_child/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Parent-to-Child Communication</title>\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body class=\"page\"></body>\n</html>\n"
  },
  {
    "path": "examples/communication_parent_to_child/index.scss",
    "content": ".page {\n    min-height: 100vh;\n    min-width: 100vw;\n\n    line-height: 1.5;\n    tab-size: 4;\n    font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n    font-feature-settings: normal;\n\n    margin: 0;\n    line-height: inherit;\n}\n\n.parent {\n    color: rgb(244 244 245);\n    background-color: rgb(24 24 27);\n\n    justify-content: center;\n    align-items: center;\n    flex-direction: column;\n    display: flex;\n\n    min-height: 100vh;\n    min-width: 100vw;\n}\n\n.title {\n    font-size: 2.25rem;\n    line-height: 2.5rem;\n    font-weight: inherit;\n\n    margin: 0;\n    margin-bottom: 2rem;\n}\n\n// Bodies\n\n.parent-body, .child-body {\n    border-width: 4px;\n    border-radius: 1rem;\n\n    border-style: solid;\n}\n\n.parent-body {\n    border-color: rgb(22 163 74);\n}\n\n.child-body {\n    border-color: rgb(249 115 22);\n\n    flex-grow: 1;\n}\n\n// Tags\n\n.parent-tag, .child-tag {\n    font-weight: 500;\n\n    padding-bottom: 0.25rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    border-top-left-radius: 0.25rem;\n    border-top-right-radius: 0.25rem;\n\n    line-height: 24px;\n}\n\n.parent-tag {\n    background-color: rgb(22 163 74);\n}\n\n.child-tag {\n    background-color: rgb(249 115 22);\n}\n\n// Content\n\n.parent-content {\n    padding-top: 1.25rem;\n    padding-bottom: 1.25rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n\n    flex-direction: column;\n    display: flex;\n}\n\n.parent-content > button {\n    font-weight: 500;\n    font-size: 1.125rem;\n    line-height: 1.75rem;\n    text-transform: none;\n    font-family: inherit;\n\n    padding-top: 0.25rem;\n    padding-bottom: 0.5rem;\n    padding-left: 0.75rem;\n    padding-right: 0.75rem;\n\n    margin-bottom: 1.25rem;\n\n    background-color: rgb(22 163 74);\n\n    border-radius: 0.75rem;\n    border-width: 0;\n    color: rgb(244 244 245);\n    cursor: pointer;\n}\n\n.parent-content > button:hover {\n    background-color: rgb(22 101 52);\n}\n\n.child-content {\n    padding-top: 0.75rem;\n    padding-bottom: 0.75rem;\n    padding-left: 1.25rem;\n    padding-right: 1.25rem;\n}\n\n.child-content > span {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n}\n\n.child-content > span > span {\n    font-weight: 700;\n}"
  },
  {
    "path": "examples/communication_parent_to_child/src/child.rs",
    "content": "use super::*;\n\n/// The `Child` component is the child of the `Parent` component, and will receive updates from the\n/// parent using properties.\npub struct Child;\n\n#[derive(Clone, Eq, PartialEq, Properties)]\npub struct ChildProps {\n    pub clicks: u32,\n}\n\nimpl Component for Child {\n    type Message = ();\n    type Properties = ChildProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {}\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"child-body\">\n                <div class=\"child-tag\">\n                    <span>{ \"Child\" }</span>\n                </div>\n                <div class=\"child-content\">\n                    <span>{ \"My parent has been clicked \" }<span>{ ctx.props().clicks }</span>{ \" times.\" }</span>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/communication_parent_to_child/src/main.rs",
    "content": "use child::Child;\nuse parent::Parent;\nuse yew::{html, Component, Context, Html, Properties};\n\nmod child;\nmod parent;\n\nfn main() {\n    yew::Renderer::<Parent>::new().render();\n}\n"
  },
  {
    "path": "examples/communication_parent_to_child/src/parent.rs",
    "content": "use super::*;\n\n/// The `Parent` component holds some state that is passed down to the children.\npub struct Parent {\n    /// The total number of clicks received\n    nr_of_clicks: u32,\n}\n\npub enum Msg {\n    ButtonClick,\n}\n\nimpl Component for Parent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self { nr_of_clicks: 0 }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ButtonClick => {\n                self.nr_of_clicks += 1;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::ButtonClick);\n\n        // Here we pass down \"our\" nr_of_clicks to the child by setting the \"clicks\" property.\n        let clicks = self.nr_of_clicks;\n\n        html! {\n            <div class=\"parent\">\n                <div>\n                    <h2 class=\"title\">{ \"Parent-to-Child Communication Example\" }</h2>\n                    <div class=\"parent-body\">\n                        <div class=\"parent-tag\">\n                            <span>{ \"Parent\" }</span>\n                        </div>\n                        <div class=\"parent-content\">\n                            <button {onclick}>{\"Click\"}</button>\n                            <Child {clicks} />\n                        </div>\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/contexts/Cargo.toml",
    "content": "[package]\nname = \"contexts\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nyew-agent = { path = \"../../packages/yew-agent\" }\n"
  },
  {
    "path": "examples/contexts/README.md",
    "content": "# Context Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fcontexts)](https://examples.yew.rs/contexts)\n\nThis is currently a technical demonstration of Context API.\n\n## Concepts\n\nThe example has two components, which communicates through a context\nas opposed to the traditional method using component links.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/contexts/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/contexts/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Context</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/contexts/src/main.rs",
    "content": "mod msg_ctx;\nmod producer;\nmod struct_component_producer;\nmod struct_component_subscriber;\nmod subscriber;\n\nuse msg_ctx::MessageProvider;\nuse producer::Producer;\nuse struct_component_producer::StructComponentProducer;\nuse struct_component_subscriber::StructComponentSubscriber;\nuse subscriber::Subscriber;\nuse yew::prelude::*;\n\n#[function_component]\npub fn App() -> Html {\n    html! {\n        <MessageProvider>\n            <Producer />\n            <StructComponentProducer />\n            <Subscriber />\n            <StructComponentSubscriber />\n        </MessageProvider>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/contexts/src/msg_ctx.rs",
    "content": "use std::rc::Rc;\n\nuse yew::prelude::*;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct Message {\n    pub inner: String,\n}\n\nimpl Reducible for Message {\n    type Action = String;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        Message { inner: action }.into()\n    }\n}\n\npub type MessageContext = UseReducerHandle<Message>;\n\n#[derive(Properties, Debug, PartialEq)]\npub struct MessageProviderProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[function_component]\npub fn MessageProvider(props: &MessageProviderProps) -> Html {\n    let msg = use_reducer(|| Message {\n        inner: \"No message yet.\".to_string(),\n    });\n\n    html! {\n        <ContextProvider<MessageContext> context={msg}>\n            {props.children.clone()}\n        </ContextProvider<MessageContext>>\n    }\n}\n"
  },
  {
    "path": "examples/contexts/src/producer.rs",
    "content": "use yew::prelude::*;\n\nuse super::msg_ctx::MessageContext;\n\n#[function_component]\npub fn Producer() -> Html {\n    let msg_ctx = use_context::<MessageContext>().unwrap();\n\n    html! {\n        <button onclick={move |_| msg_ctx.dispatch(\"Message Received.\".to_string())}>\n            {\"PRESS ME\"}\n        </button>\n    }\n}\n"
  },
  {
    "path": "examples/contexts/src/struct_component_producer.rs",
    "content": "use yew::prelude::*;\n\nuse super::msg_ctx::MessageContext;\n\npub struct StructComponentProducer;\n\nimpl Component for StructComponentProducer {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let (msg_ctx, _) = ctx\n            .link()\n            .context::<MessageContext>(Callback::noop())\n            .expect(\"No Message Context Provided\");\n\n        html! {\n            <button onclick={move |_| msg_ctx.dispatch(\"Other message received.\".to_owned())}>\n                {\"OR ME\"}\n            </button>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/contexts/src/struct_component_subscriber.rs",
    "content": "use yew::prelude::*;\n\nuse super::msg_ctx::MessageContext;\n\npub enum Msg {\n    MessageContextUpdated(MessageContext),\n}\n\npub struct StructComponentSubscriber {\n    message: MessageContext,\n    _context_listener: ContextHandle<MessageContext>,\n}\n\nimpl Component for StructComponentSubscriber {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let (message, context_listener) = ctx\n            .link()\n            .context(ctx.link().callback(Msg::MessageContextUpdated))\n            .expect(\"No Message Context Provided\");\n\n        Self {\n            message,\n            _context_listener: context_listener,\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::MessageContextUpdated(message) => {\n                self.message = message;\n                true\n            }\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            <h1>{ self.message.inner.to_string() }</h1>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/contexts/src/subscriber.rs",
    "content": "use yew::prelude::*;\n\nuse super::msg_ctx::MessageContext;\n\n#[function_component]\npub fn Subscriber() -> Html {\n    let msg_ctx = use_context::<MessageContext>().unwrap();\n\n    let message = msg_ctx.inner.to_owned();\n\n    html! {\n        <h1>{ message }</h1>\n    }\n}\n"
  },
  {
    "path": "examples/counter/Cargo.toml",
    "content": "[package]\nname = \"counter\"\nversion = \"0.1.1\"\nauthors = [\"Denis Kolodin <deniskolodin@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\ngloo.workspace = true\njs-sys.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nwasm-bindgen.workspace = true\n"
  },
  {
    "path": "examples/counter/README.md",
    "content": "# Counter Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fcounter)](https://examples.yew.rs/counter)\n\nA simple example of a counter which can be increased or decreased with the press of a button.\n\n## Concepts\n\nDemonstrates the use of messages to update state.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/counter/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/counter/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Counter</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/counter/index.scss",
    "content": "button {\n  background-color: #008f53; /* Green */\n  border: 0;\n  color: white;\n  padding: 14px 14px;\n  text-align: center;\n  font-size: 16px;\n  margin: 2px 2px;\n  width: 100px;\n}\n\n.counter {\n    color: #008f53;\n    font-size: 48px;\n    text-align: center;\n}\n\n.footer {\n    text-align: center;\n    font-size: 12px;\n}\n\n.panel {\n  display: flex;\n  justify-content: center;\n}\n"
  },
  {
    "path": "examples/counter/src/main.rs",
    "content": "use gloo::console;\nuse js_sys::Date;\nuse yew::{html, Component, Context, Html};\n\n// Define the possible messages which can be sent to the component\npub enum Msg {\n    Increment,\n    Decrement,\n}\n\npub struct App {\n    value: i64, // This will store the counter value\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self { value: 0 }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Increment => {\n                self.value += 1;\n                console::log!(\"plus one\"); // Will output a string to the browser console\n                true // Return true to cause the displayed change to update\n            }\n            Msg::Decrement => {\n                self.value -= 1;\n                console::log!(\"minus one\");\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div>\n                <div class=\"panel\">\n                    // A button to send the Increment message\n                    <button class=\"button\" onclick={ctx.link().callback(|_| Msg::Increment)}>\n                        { \"+1\" }\n                    </button>\n\n                    // A button to send the Decrement message\n                    <button onclick={ctx.link().callback(|_| Msg::Decrement)}>\n                        { \"-1\" }\n                    </button>\n\n                    // A button to send two Increment messages\n                    <button onclick={ctx.link().batch_callback(|_| vec![Msg::Increment, Msg::Increment])}>\n                        { \"+1, +1\" }\n                    </button>\n\n                </div>\n\n                // Display the current value of the counter\n                <p class=\"counter\">\n                    { self.value }\n                </p>\n\n                // Display the current date and time the page was rendered\n                <p class=\"footer\">\n                    { \"Rendered: \" }\n                    { String::from(Date::new_0().to_string()) }\n                </p>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/counter_functional/Cargo.toml",
    "content": "[package]\nname = \"counter_functional\"\nversion = \"0.1.0\"\nauthors = [\"Zahash <zahash.z@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/counter_functional/README.md",
    "content": "# Counter Example\n\nA simple example of a counter which can be increased or decreased with the press of a button implemented using function components\n\n## Concepts\n\nDemonstrates the use of function components.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/counter_functional/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/counter_functional/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Counter Function Yew</title>\n    <link data-trunk rel=\"rust\" />\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/counter_functional/src/main.rs",
    "content": "use yew::prelude::*;\n\n#[function_component]\nfn App() -> Html {\n    let state = use_state(|| 0);\n\n    let incr_counter = {\n        let state = state.clone();\n        Callback::from(move |_| state.set(*state + 1))\n    };\n\n    let decr_counter = {\n        let state = state.clone();\n        Callback::from(move |_| state.set(*state - 1))\n    };\n\n    html! {\n        <>\n            <p> {\"current count: \"} {*state} </p>\n            <button onclick={incr_counter}> {\"+\"} </button>\n            <button onclick={decr_counter}> {\"-\"} </button>\n        </>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/dyn_create_destroy_apps/Cargo.toml",
    "content": "[package]\nname = \"dyn_create_destroy_apps\"\nversion = \"0.1.0\"\nauthors = [\"Nicklas Warming Jacobsen <nicklaswj@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\njs-sys.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nslab = \"0.4.12\"\ngloo.workspace = true\nwasm-bindgen.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"Document\",\n    \"Element\",\n    \"Node\",\n    \"DomTokenList\"\n]\n"
  },
  {
    "path": "examples/dyn_create_destroy_apps/README.md",
    "content": "# Dynamic app creation and destruction example\n\nAn example of how to create and destroy Yew apps on demand.\n\n## Concepts\n\nDemonstrates the use of the Yew app handle by dynamically creating and destroying apps.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/dyn_create_destroy_apps/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/dyn_create_destroy_apps/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Create and destroy apps</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/dyn_create_destroy_apps/index.scss",
    "content": "button {\n  border: 0;\n  color: white;\n  padding: 14px 14px;\n  text-align: center;\n  font-size: 16px;\n}\n\nbutton.create {\n  background-color: #008f53; /* Green */\n  width: 200px;\n}\n\nbutton.destroy {\n  background-color: #ff1f1f; /* Red */\n}\n\n.counter {\n  color: #008f53;\n  font-size: 48px;\n  text-align: center;\n}\n\n.panel {\n  display: flex;\n  justify-content: center;\n}\n"
  },
  {
    "path": "examples/dyn_create_destroy_apps/src/counter.rs",
    "content": "use gloo::console;\nuse gloo::timers::callback::Interval;\nuse yew::prelude::*;\n\npub struct CounterModel {\n    counter: usize,\n    _interval: Interval,\n}\n\n#[derive(Clone, Properties, PartialEq)]\npub struct CounterProps {\n    pub destroy_callback: Callback<()>,\n}\n\npub enum CounterMessage {\n    Tick,\n}\n\nimpl Component for CounterModel {\n    type Message = CounterMessage;\n    type Properties = CounterProps;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        // Create a Tick message every second\n        let link = ctx.link().clone();\n        let interval = Interval::new(1, move || link.send_message(Self::Message::Tick));\n        Self {\n            counter: 0,\n            _interval: interval,\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            // Count our internal state up by one\n            Self::Message::Tick => {\n                self.counter += 1;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let destroy_callback = ctx.props().destroy_callback.clone();\n\n        html! {\n            <>\n                // Display the current value of the counter\n                <p class=\"counter\">\n                    { \"App has lived for \" }\n                    { self.counter }\n                    { \" ticks\" }\n                </p>\n\n                // Add button to send a destroy command to the parent app\n                <button class=\"destroy\" onclick={Callback::from(move |_| destroy_callback.emit(()))}>\n                    { \"Destroy this app\" }\n                </button>\n            </>\n        }\n    }\n\n    fn destroy(&mut self, _ctx: &Context<Self>) {\n        console::log!(\"CounterModel app destroyed\");\n    }\n}\n"
  },
  {
    "path": "examples/dyn_create_destroy_apps/src/main.rs",
    "content": "use gloo::utils::document;\nuse slab::Slab;\nuse web_sys::Element;\nuse yew::prelude::*;\n\nmod counter;\n\nuse counter::{CounterModel, CounterProps};\n\n// Define the possible messages which can be sent to the component\npub enum Msg {\n    // Spawns a new instance of the CounterModel app\n    SpawnCounterAppInstance,\n    // Destroys an instance of a CounterModel app\n    DestroyCounterApp(usize),\n}\n\npub struct App {\n    apps: Slab<(Element, AppHandle<CounterModel>)>, /* Contains the spawned apps and their\n                                                     * parent div elements */\n    apps_container_ref: NodeRef,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            apps: Slab::new(),\n            apps_container_ref: NodeRef::default(),\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        let app_container = self\n            .apps_container_ref\n            .cast::<Element>()\n            .expect(\"Failed to cast app container div to HTMLElement\");\n\n        match msg {\n            Msg::SpawnCounterAppInstance => {\n                // Create a new <div> HtmlElement where the new app will live\n                let app_div = document()\n                    .create_element(\"div\")\n                    .expect(\"Failed to create <div> element\");\n\n                // Append the div to the document body\n                let _ = app_container\n                    .append_child(&app_div)\n                    .expect(\"Failed to append app div app container div\");\n\n                // Reserve an entry for the new app\n                let app_entry = self.apps.vacant_entry();\n\n                // Get the key for the entry and create and mount a new CounterModel app\n                // with a callback that destroys the app when emitted\n                let app_key = app_entry.key();\n                let new_counter_app = yew::Renderer::<CounterModel>::with_root_and_props(\n                    app_div.clone(),\n                    CounterProps {\n                        destroy_callback: ctx\n                            .link()\n                            .callback(move |_| Msg::DestroyCounterApp(app_key)),\n                    },\n                )\n                .render();\n\n                // Insert the app and the app div to our app collection\n                app_entry.insert((app_div, new_counter_app));\n            }\n            Msg::DestroyCounterApp(app_id) => {\n                // Get the app from the app slabmap\n                let (app_div, app) = self.apps.remove(app_id);\n\n                // Destroy the app\n                app.destroy();\n\n                // Remove the app div from the DOM\n                app_div.remove()\n            }\n        }\n\n        // Never render\n        false\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // We will only render once, and then do the rest of the DOM changes\n        // by mounting/destroying appinstances of CounterModel\n        html! {\n            <>\n                <div class=\"panel\">\n                    // Create button to create a new app\n                    <button\n                        class=\"create\"\n                        onclick={ctx.link().callback(|_| Msg::SpawnCounterAppInstance)}\n                    >\n                        { \"Spawn new CounterModel app\" }\n                    </button>\n                </div>\n                // Create a container for all the app instances\n                <div ref={self.apps_container_ref.clone()}>\n                </div>\n            </>\n        }\n    }\n}\n\nfn main() {\n    // Start main app\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/file_upload/Cargo.toml",
    "content": "[package]\nname = \"file_upload\"\nversion = \"0.1.0\"\nauthors = [\"Denis Kolodin <deniskolodin@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\njs-sys.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nbase64 = \"0.22.1\"\ngloo.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\"DataTransfer\"]\n"
  },
  {
    "path": "examples/file_upload/README.md",
    "content": "# File Upload Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffile_upload)](https://examples.yew.rs/file_upload)\n\nThis example allows the user to select a file from their file system.\nThe contents of the selected file are then rendered to the page either as a whole or in chunks.\n\n## Concepts\n\nDemonstrates reading from files in Yew with the help of [`gloo::file`](https://docs.rs/gloo-file/latest/gloo_file/).\n\n## Improvements\n\n- Show a progress bar if the file is read in chunks\n- Do something interesting with the uploaded file like displaying pictures\n- Improve the presentation of the example with CSS.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/file_upload/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/file_upload/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • File Upload</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"css\" href=\"./styles.css\" />\n    <link\n      rel=\"stylesheet\"\n      href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css\"\n    />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/file_upload/src/main.rs",
    "content": "extern crate base64;\nuse std::collections::HashMap;\n\nuse base64::engine::general_purpose::STANDARD;\nuse base64::Engine;\nuse gloo::file::callbacks::FileReader;\nuse web_sys::{DragEvent, Event, HtmlInputElement};\nuse yew::html::TargetCast;\nuse yew::{html, Callback, Component, Context, Html};\n\npub struct FileDetails {\n    name: String,\n    file_type: String,\n    data: Vec<u8>,\n}\n\npub enum Msg {\n    Loaded(FileDetails),\n    Files(Option<web_sys::FileList>),\n}\n\npub struct App {\n    readers: HashMap<String, FileReader>,\n    files: Vec<FileDetails>,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            readers: HashMap::default(),\n            files: Vec::default(),\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Loaded(file) => {\n                self.readers.remove(&file.name);\n                self.files.push(file);\n                true\n            }\n            Msg::Files(files) => {\n                for file in gloo::file::FileList::from(files.expect(\"files\")).iter() {\n                    let link = ctx.link().clone();\n                    let name = file.name().clone();\n                    let file_type = file.raw_mime_type();\n\n                    let task = {\n                        gloo::file::callbacks::read_as_bytes(file, move |res| {\n                            link.send_message(Msg::Loaded(FileDetails {\n                                data: res.expect(\"failed to read file\"),\n                                file_type,\n                                name,\n                            }))\n                        })\n                    };\n                    self.readers.insert(file.name(), task);\n                }\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let noop_drag = Callback::from(|e: DragEvent| {\n            e.prevent_default();\n        });\n\n        html! {\n            <div id=\"wrapper\">\n                <p id=\"title\">{ \"Upload Your Files To The Cloud\" }</p>\n                <label for=\"file-upload\">\n                    <div\n                        id=\"drop-container\"\n                        ondrop={ctx.link().callback(|event: DragEvent| {\n                            event.prevent_default();\n                            Msg::Files(event.data_transfer().unwrap().files())\n                        })}\n                        ondragover={&noop_drag}\n                        ondragenter={&noop_drag}\n                    >\n                        <i class=\"fa fa-cloud-upload\"></i>\n                        <p>{\"Drop your images here or click to select\"}</p>\n                    </div>\n                </label>\n                <input\n                    id=\"file-upload\"\n                    type=\"file\"\n                    accept=\"image/*,video/*\"\n                    multiple={true}\n                    onchange={ctx.link().callback(move |e: Event| {\n                        let input: HtmlInputElement = e.target_unchecked_into();\n                        Msg::Files(input.files())\n                    })}\n                />\n                <div id=\"preview-area\">\n                    { for self.files.iter().map(Self::view_file) }\n                </div>\n            </div>\n        }\n    }\n}\n\nimpl App {\n    fn view_file(file: &FileDetails) -> Html {\n        let file_type = file.file_type.to_string();\n        let src = format!(\"data:{};base64,{}\", file_type, STANDARD.encode(&file.data));\n        html! {\n            <div class=\"preview-tile\">\n                <p class=\"preview-name\">{ &file.name }</p>\n                <div class=\"preview-media\">\n                    if file.file_type.contains(\"image\") {\n                        <img src={src} />\n                    } else if file.file_type.contains(\"video\") {\n                        <video controls={true}>\n                            <source src={src} type={ file_type }/>\n                        </video>\n                    }\n                </div>\n            </div>\n        }\n    }\n}\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/file_upload/styles.css",
    "content": "* {\n  box-sizing: border-box;\n  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;\n}\n\nhtml,\nbody {\n  margin: 0;\n  padding: 0;\n  background: #2d3131;\n  color: #fcfcfc;\n}\n\nimg,\nvideo {\n  max-width: 300px;\n  max-height: 500px;\n}\n\np {\n  text-align: center;\n}\n\nlabel {\n  cursor: pointer;\n}\n\ninput#file-upload {\n  visibility: hidden;\n}\n\n#wrapper {\n  width: 70%;\n  margin: auto;\n}\n\n#title {\n  font-size: 2rem;\n  text-align: center;\n}\n\n#drop-container {\n  padding: 4rem;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  background: #3d4141;\n  border: 1px dashed #fcfcfc;\n  border-radius: 1rem;\n}\n\n#drop-container i {\n  font-size: 4rem;\n}\n\n#preview-area {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  align-items: stretch;\n}\n\n.preview-tile {\n  display: flex;\n  flex-direction: column;\n  padding: 2rem;\n  margin: 1rem;\n  background: #313737;\n  border-radius: 1rem;\n}\n\n.preview-media {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n}\n"
  },
  {
    "path": "examples/function_delayed_input/Cargo.toml",
    "content": "[package]\nname = \"function_delayed_input\"\nversion = \"0.1.0\"\nauthors = [\"Ruslan Sibgatullin <info@pudding.pro>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\ngloo-timers = { version = \"0.3.0\", features = [\"futures\"] }\nweb-sys = { workspace = true, features = [\"Window\"]}\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/function_delayed_input/README.md",
    "content": "# Delayed Input Processing Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffunction_delayed_input)](https://examples.yew.rs/function_delayed_input)\n\nThis is a demonstration of how to create an input form with delayed input processing.\n\nA typical use case is to send user input to the backend only when they have stopped typing, rather than on every keystroke.\n\n## Concepts\n- Uses [`gloo-timers`](https://crates.io/crates/gloo-timers) to delay the processing\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```\n"
  },
  {
    "path": "examples/function_delayed_input/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/function_delayed_input/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>Yew • Function Delayed Input</title>\n\n    <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65\" crossorigin=\"anonymous\">\n    <link data-trunk rel=\"rust\"/>\n</head>\n<body></body>\n</html>\n"
  },
  {
    "path": "examples/function_delayed_input/src/main.rs",
    "content": "use std::time::Duration;\n\nuse gloo_timers::callback::Timeout;\nuse web_sys::wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::*;\n\n#[component]\nfn App() -> Html {\n    #[derive(PartialEq, Default, Clone)]\n    enum Search {\n        #[default]\n        Idle,\n        Fetching(AttrValue),\n        Fetched(AttrValue),\n    }\n\n    let search = use_state(Search::default);\n\n    use_effect_with(search.clone(), {\n        move |search| {\n            // here you would typically do a REST call to send the search input to backend\n            // for simplicity sake here we just set back the original input\n            if let Search::Fetching(query) = &**search {\n                yew::platform::spawn_local({\n                    let query = query.clone();\n                    let search = search.setter();\n                    async move {\n                        // Simulate a network delay\n                        gloo_timers::future::sleep(Duration::from_millis(500)).await;\n                        search.set(Search::Fetched(\n                            format!(\"Placeholder response for: {}\", query).into(),\n                        ));\n                    }\n                });\n            }\n        }\n    });\n\n    let oninput = {\n        let timeout_ref = use_mut_ref(|| None);\n        use_callback((), {\n            let search = search.clone();\n            move |e: InputEvent, _| {\n                if let Some(target) = e.target() {\n                    let input = target.dyn_into::<HtmlInputElement>().ok();\n                    if let Some(input) = input {\n                        let value = input.value();\n                        if !value.is_empty() {\n                            let search = search.setter();\n                            let timeout = Timeout::new(1_000, move || {\n                                search.set(Search::Fetching(value.into()));\n                            });\n                            (*timeout_ref.borrow_mut()) = Some(timeout);\n                        }\n                    }\n                }\n            }\n        })\n    };\n\n    html! {\n      <div class=\"container p-2\">\n          <div class=\"row\">\n            <div class=\"p-2\">\n              <form class=\"input-group bg-dark border border-white rounded\">\n                <input id=\"search\" autocomplete=\"off\" type=\"search\" class=\"form-control\" placeholder=\"Type something here...\" aria-label=\"Search\" {oninput}/>\n              </form>\n            </div>\n            <div class=\"p-2 border border-black rounded\">\n                <p>{\n                    match &*search {\n                        Search::Idle => \"Type something to search...\".into(),\n                        Search::Fetching(query) => format!(\"Searching for: {}\", query).into(),\n                        Search::Fetched(response) => response.clone(),\n                    }\n                }</p>\n            </div>\n          </div>\n      </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/function_memory_game/Cargo.toml",
    "content": "[package]\nname = \"function_memory_game\"\nversion = \"0.1.0\"\nauthors = [\"Howard.Zuo <leftstick@qq.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nserde = { workspace = true, features = [\"derive\"] }\nstrum.workspace = true\nstrum_macros.workspace = true\ngloo.workspace = true\nnanoid = \"0.4\"\nrand.workspace = true\ngetrandom = { workspace = true }\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n\t\"HtmlInputElement\",\n]\n"
  },
  {
    "path": "examples/function_memory_game/README.md",
    "content": "# Memory Game Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffunction_memory_game)](https://examples.yew.rs/function_memory_game)\n\nThis is an implementation of [Memory Game](https://github.com/bradlygreen/Memory-Game) for Yew using function components and hooks.\n\n## Concepts\n\n- Uses [`function_components`](https://yew.rs/docs/next/concepts/function-components)\n- Uses [`gloo::storage`](https://docs.rs/gloo-storage/0.2.0/gloo_storage/index.html) to persist the state\n- Uses [`gloo::timers`](https://docs.rs/gloo-timers/0.2.2/gloo_timers/index.html) to schedule asynchronous callback\n\n## Note\n\nImages are authorized by [@bradlygreen](https://github.com/bradlygreen), see [authorization-issue](https://github.com/bradlygreen/Memory-Game/issues/6)\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\nRUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' trunk serve --open\n```\n"
  },
  {
    "path": "examples/function_memory_game/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/function_memory_game/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <link rel=\"icon\" href=\"public/favicon.ico\" />\n    <title>Yew • Function Memory Game</title>\n    <base data-trunk-public-url />\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"scss/index.scss\" />\n    <link data-trunk rel=\"copy-dir\" href=\"public/\" />\n    \n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/function_memory_game/scss/chess_board.scss",
    "content": ".chess-board {\n  margin-top: 20px;\n  width: 100%;\n  background-color: #fff;\n  height: 530px;\n  border-radius: 4px;\n  padding: 10px 5px;\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  align-items: center;\n  align-content: space-around;\n  .chess-board-card-container:nth-child(4n) {\n    margin-right: 0px;\n  }\n}\n\n@media screen and (max-width: 450px) {\n  .chess-board {\n    height: 480px;\n    padding: 10px 0px;\n  }\n}\n@media screen and (max-width: 370px) {\n  .chess-board {\n    height: 450px;\n  }\n}\n"
  },
  {
    "path": "examples/function_memory_game/scss/chess_board_card.scss",
    "content": ".chess-board-card-container {\n  width: 100px;\n  height: 121px;\n  margin-right: 3px;\n  cursor: pointer;\n  position: relative;\n  perspective: 800px;\n\n  .card {\n    width: 100%;\n    height: 100%;\n    transition: transform 1s;\n    transform-style: preserve-3d;\n  }\n\n  .card.flipped {\n    transform: rotateY(180deg);\n  }\n\n  .card img {\n    display: block;\n    height: 100%;\n    width: 100%;\n    position: absolute;\n    backface-visibility: hidden;\n  }\n\n  .card .back {\n    background: blue;\n    transform: rotateY(0deg);\n  }\n\n  .card .front {\n    background: blue;\n    transform: rotateY(180deg);\n  }\n}\n\n@media screen and (max-width: 450px) {\n  .chess-board-card-container {\n    width: 92px;\n    height: 111px;\n    margin-right: 1px;\n  }\n}\n\n@media screen and (max-width: 395px) {\n  .chess-board-card-container {\n    width: 85px;\n    height: 102px;\n    margin-right: 1px;\n  }\n}\n\n@media screen and (max-width: 360px) {\n  .chess-board-card-container {\n    width: 70px;\n    height: 84px;\n    margin-right: 1px;\n  }\n}\n"
  },
  {
    "path": "examples/function_memory_game/scss/game_progress.scss",
    "content": ".game-progress {\n  width: 120px;\n  height: 100px;\n  padding: 10px;\n  background-color: #bbada0;\n  border-radius: 5px;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: center;\n  color: #eae0d1;\n\n  span {\n    font-size: 19px;\n    font-weight: bold;\n    display: block;\n    width: 100%;\n    text-align: center;\n  }\n\n  h2 {\n    color: #fff;\n  }\n}\n\n@media screen and (max-width: 450px) {\n  .game-progress {\n    width: 105px;\n    span {\n      font-size: 17px;\n    }\n  }\n}\n\n@media screen and (max-width: 380px) {\n  .game-progress {\n    width: 95px;\n  }\n}\n\n@media screen and (max-width: 360px) {\n  .game-progress {\n    width: 90px;\n    span {\n      font-size: 15px;\n    }\n  }\n}\n"
  },
  {
    "path": "examples/function_memory_game/scss/game_status_board.scss",
    "content": ".game-status-container {\n  position: relative;\n  margin-top: 10px;\n  width: 100%;\n  height: 20px;\n  line-height: 20px;\n  text-align: center;\n  font-size: 18px;\n  font-weight: bold;\n  button {\n    border: none;\n    cursor: pointer;\n    background: transparent;\n    color: #5979ac;\n    font-size: 17px;\n    font-weight: bold;\n  }\n  .sec-past {\n    position: absolute;\n    right: 10px;\n    font-size: 15px;\n    font-weight: normal;\n  }\n}\n"
  },
  {
    "path": "examples/function_memory_game/scss/index.scss",
    "content": "* {\n  box-sizing: border-box;\n  padding: 0;\n  margin: 0;\n}\n\nhtml,\nbody {\n  height: 100vh;\n  width: 100vw;\n  margin: 0;\n  padding: 0;\n}\n\nbody {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n\n.game-panel {\n  width: 450px;\n  height: 670px;\n  border: 4px solid #bdbdbd;\n  border-radius: 2px;\n  background-color: #faf8ef;\n  padding: 10px;\n  display: flex;\n  flex-direction: column;\n}\n\n@media screen and (max-width: 450px) {\n  .game-panel {\n    width: 100%;\n    height: 100%;\n    justify-content: space-around;\n  }\n}\n\n@import './score_board.scss';\n@import './score_board_best_score.scss';\n@import './game_progress';\n@import './chess_board.scss';\n@import './chess_board_card.scss';\n@import './game_status_board.scss';\n"
  },
  {
    "path": "examples/function_memory_game/scss/score_board.scss",
    "content": ".score-board {\n  width: 100%;\n  height: 100px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  .logo {\n    width: 160px;\n    height: 100px;\n    line-height: 90px;\n    padding: 5px;\n    border-radius: 5px;\n    background-color: #5979ac;\n    color: #fff;\n    text-align: center;\n  }\n  a {\n    text-decoration: none;\n    color: #fff;\n  }\n}\n\n// score board -> logo\n\n@media screen and (max-width: 450px) {\n  .score-board .logo {\n    width: 150px;\n  }\n}\n\n@media screen and (max-width: 380px) {\n  .score-board .logo {\n    width: 140px;\n  }\n}\n\n@media screen and (max-width: 360px) {\n  .score-board {\n    .logo {\n      width: 110px;\n    }\n    a {\n      font-size: 18px;\n    }\n  }\n}\n"
  },
  {
    "path": "examples/function_memory_game/scss/score_board_best_score.scss",
    "content": ".best-score {\n  width: 120px;\n  height: 100px;\n  padding: 10px;\n  background-color: #bbada0;\n  border-radius: 5px;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: center;\n  color: #eae0d1;\n  span {\n    font-size: 19px;\n    font-weight: bold;\n    display: block;\n    width: 100%;\n    text-align: center;\n  }\n\n  h2 {\n    color: #fff;\n  }\n}\n\n@media screen and (max-width: 450px) {\n  .best-score {\n    width: 105px;\n    span {\n      font-size: 17px;\n    }\n  }\n}\n@media screen and (max-width: 380px) {\n  .best-score {\n    width: 95px;\n  }\n}\n\n@media screen and (max-width: 360px) {\n  .best-score {\n    width: 90px;\n    span {\n      font-size: 15px;\n    }\n  }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/app.rs",
    "content": "use std::cell::RefCell;\nuse std::rc::Rc;\n\nuse gloo::timers::callback::{Interval, Timeout};\nuse yew::prelude::*;\nuse yew::{function_component, html};\n\nuse crate::components::chessboard::Chessboard;\nuse crate::components::game_status_board::GameStatusBoard;\nuse crate::components::score_board::ScoreBoard;\nuse crate::constant::Status;\nuse crate::state::{Action, State};\n\n#[function_component]\npub fn App() -> Html {\n    let state = use_reducer(State::reset);\n    let sec_past = use_state(|| 0_u32);\n    let sec_past_timer: Rc<RefCell<Option<Interval>>> = use_mut_ref(|| None);\n    let limit_flips_timer: Rc<RefCell<Option<Timeout>>> = use_mut_ref(|| None);\n    let sec_past_time = *sec_past;\n\n    use_effect_with(state.clone(), {\n        let limit_flips_timer = limit_flips_timer.clone();\n        move |state| {\n            // game reset\n            if state.status == Status::Ready {\n                sec_past.set(0);\n            }\n            // game start\n            else if *sec_past == 0 && state.last_card.is_some() {\n                let sec_past = sec_past.clone();\n                let mut sec = *sec_past;\n                *sec_past_timer.borrow_mut() = Some(Interval::new(1000, move || {\n                    sec += 1;\n                    sec_past.set(sec);\n                }));\n            }\n            // game over\n            else if state.status == Status::Passed {\n                *sec_past_timer.borrow_mut() = None;\n                *limit_flips_timer.borrow_mut() = None;\n                state.dispatch(Action::TrySaveBestScore(*sec_past));\n            }\n            // match failed\n            else if state.rollback_cards.is_some() {\n                let cloned_state = state.clone();\n                let cloned_rollback_cards = state.rollback_cards.clone().unwrap();\n                *limit_flips_timer.borrow_mut() = Some(Timeout::new(1000, {\n                    let limit_flips_timer = limit_flips_timer.clone();\n                    move || {\n                        limit_flips_timer.borrow_mut().take();\n                        cloned_state.dispatch(Action::RollbackCards(cloned_rollback_cards));\n                    }\n                }));\n            }\n            || ()\n        }\n    });\n\n    let on_reset = {\n        let state = state.clone();\n        Callback::from(move |_| state.dispatch(Action::GameReset))\n    };\n\n    let on_flip = {\n        let state = state.clone();\n        Callback::from(move |card| {\n            if limit_flips_timer.borrow().is_some() {\n                return;\n            }\n\n            *limit_flips_timer.borrow_mut() = Some(Timeout::new(1000, {\n                let limit_flips_timer = limit_flips_timer.clone();\n                move || {\n                    limit_flips_timer.borrow_mut().take();\n                }\n            }));\n\n            state.dispatch(Action::FlipCard(card));\n        })\n    };\n\n    html! {\n        <div class=\"game-panel\">\n            <ScoreBoard unresolved_card_pairs={state.unresolved_card_pairs} best_score={state.best_score} />\n            <Chessboard cards={state.cards.clone()} {on_flip} />\n            <GameStatusBoard sec_past={sec_past_time} status={state.status} {on_reset}/>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/chessboard.rs",
    "content": "use yew::prelude::*;\nuse yew::{function_component, html, Properties};\n\nuse crate::components::chessboard_card::ChessboardCard;\nuse crate::state::{Card, RawCard};\n\n#[derive(Properties, Clone, PartialEq)]\npub struct Props {\n    pub cards: Vec<Card>,\n    pub on_flip: Callback<RawCard>,\n}\n#[function_component]\npub fn Chessboard(props: &Props) -> Html {\n    html! {\n        <div class=\"chess-board\">\n        { for props.cards.iter().map(|card|\n            html! {\n                <ChessboardCard card={card.clone()} on_flip={&props.on_flip} />\n            }\n        ) }\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/chessboard_card.rs",
    "content": "use web_sys::MouseEvent;\nuse yew::prelude::*;\nuse yew::{function_component, html, Html, Properties};\n\nuse crate::constant::CardName;\nuse crate::state::{Card, RawCard};\n\n#[derive(Properties, Clone, PartialEq)]\npub struct Props {\n    pub card: Card,\n    pub on_flip: Callback<RawCard>,\n}\n\n#[function_component]\npub fn ChessboardCard(props: &Props) -> Html {\n    let Props { card, on_flip } = props.clone();\n    let Card { flipped, name, id } = card;\n\n    let get_link_by_cardname = {\n        match name {\n            CardName::EightBall => \"public/8-ball.png\",\n            CardName::Kronos => \"public/kronos.png\",\n            CardName::BakedPotato => \"public/baked-potato.png\",\n            CardName::Dinosaur => \"public/dinosaur.png\",\n            CardName::Rocket => \"public/rocket.png\",\n            CardName::SkinnyUnicorn => \"public/skinny-unicorn.png\",\n            CardName::ThatGuy => \"public/that-guy.png\",\n            CardName::Zeppelin => \"public/zeppelin.png\",\n        }\n        .to_string()\n    };\n\n    let onclick = move |e: MouseEvent| {\n        e.stop_propagation();\n        (!flipped).then(|| {\n            on_flip.emit(RawCard {\n                id: id.clone(),\n                name,\n            })\n        });\n    };\n\n    html! {\n      <div class=\"chess-board-card-container\">\n          <div class={classes!(\"card\", flipped.then_some(\"flipped\"))} {onclick}>\n              <img class=\"front\" src={get_link_by_cardname} alt=\"card\" />\n              <img class=\"back\" src=\"public/back.png\" alt=\"card\" />\n          </div>\n      </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/game_status_board.rs",
    "content": "use yew::prelude::*;\nuse yew::{function_component, html, Properties};\n\nuse crate::constant::Status;\n\n#[derive(Properties, Clone, PartialEq)]\npub struct Props {\n    pub status: Status,\n    pub sec_past: u32,\n    pub on_reset: Callback<()>,\n}\n\n#[function_component]\npub fn GameStatusBoard(props: &Props) -> Html {\n    let get_content = {\n        let onclick = props.on_reset.reform(move |e: MouseEvent| {\n            e.stop_propagation();\n            e.prevent_default();\n        });\n\n        match props.status {\n            Status::Ready => html! {\n                <span>{\"Ready\"}</span>\n            },\n            Status::Playing => html! {\n                <span>{\"Playing\"}</span>\n            },\n            Status::Passed => html! {\n                <button class=\"play-again-btn\" {onclick}>{\"Play again\"}</button>\n            },\n        }\n    };\n\n    html! {\n      <div class=\"game-status-container\">\n        {get_content}\n        <span class=\"sec-past\">{ props.sec_past}{\" s\"}</span>\n    </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/score_board.rs",
    "content": "use yew::{function_component, html, Html, Properties};\n\nuse crate::components::score_board_best_score::BestScore;\nuse crate::components::score_board_logo::Logo;\nuse crate::components::score_board_progress::GameProgress;\n\n#[derive(PartialEq, Properties, Clone, Eq)]\npub struct Props {\n    pub unresolved_card_pairs: u8,\n    pub best_score: u32,\n}\n\n#[function_component]\npub fn ScoreBoard(props: &Props) -> Html {\n    let Props {\n        best_score,\n        unresolved_card_pairs,\n    } = props.clone();\n    html! {\n        <div class=\"score-board\">\n            <Logo />\n            <GameProgress {unresolved_card_pairs} />\n            <BestScore {best_score} />\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/score_board_best_score.rs",
    "content": "use yew::{function_component, html, Html, Properties};\n\n#[derive(PartialEq, Eq, Properties, Clone)]\npub struct Props {\n    pub best_score: u32,\n}\n\n#[function_component]\npub fn BestScore(props: &Props) -> Html {\n    html! {\n        <div class=\"best-score\">\n            <span>{\"Highest Record\"}</span>\n            <h2>{ props.best_score }</h2>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/score_board_logo.rs",
    "content": "use yew::{function_component, html, Html};\n\n#[function_component]\npub fn Logo() -> Html {\n    html! {\n        <h1 class=\"logo\">\n            <a href=\"https://examples.yew.rs/function_memory_game\" target=\"_blank\">{\"Memory\"}</a>\n        </h1>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components/score_board_progress.rs",
    "content": "use yew::{function_component, html, Html, Properties};\n\n#[derive(PartialEq, Eq, Properties, Clone)]\npub struct Props {\n    pub unresolved_card_pairs: u8,\n}\n\n#[function_component]\npub fn GameProgress(props: &Props) -> Html {\n    html! {\n        <div class=\"game-progress\">\n            <span>{\"Cards not Matched\"}</span>\n            <h2>{ props.unresolved_card_pairs }</h2>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/components.rs",
    "content": "pub mod app;\npub mod chessboard;\npub mod chessboard_card;\npub mod game_status_board;\npub mod score_board;\npub mod score_board_best_score;\npub mod score_board_logo;\npub mod score_board_progress;\n"
  },
  {
    "path": "examples/function_memory_game/src/constant.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse strum_macros::{Display, EnumIter};\n\npub const KEY_BEST_SCORE: &str = \"memory.game.best.score\";\n\n#[derive(Clone, Copy, Debug, EnumIter, Display, PartialEq, Eq, Serialize, Deserialize)]\npub enum CardName {\n    EightBall,\n    Kronos,\n    BakedPotato,\n    Dinosaur,\n    Rocket,\n    SkinnyUnicorn,\n    ThatGuy,\n    Zeppelin,\n}\n\n#[derive(Clone, Copy, Debug, EnumIter, Display, PartialEq, Eq, Serialize, Deserialize)]\npub enum Status {\n    Ready,\n    Playing,\n    Passed,\n}\n\npub const RAW_CARDS: [CardName; 16] = [\n    CardName::EightBall,\n    CardName::Kronos,\n    CardName::BakedPotato,\n    CardName::Dinosaur,\n    CardName::Rocket,\n    CardName::SkinnyUnicorn,\n    CardName::ThatGuy,\n    CardName::Zeppelin,\n    CardName::EightBall,\n    CardName::Kronos,\n    CardName::BakedPotato,\n    CardName::Dinosaur,\n    CardName::Rocket,\n    CardName::SkinnyUnicorn,\n    CardName::ThatGuy,\n    CardName::Zeppelin,\n];\n"
  },
  {
    "path": "examples/function_memory_game/src/helper.rs",
    "content": "use nanoid::nanoid;\nuse rand::rng;\nuse rand::seq::SliceRandom;\n\nuse crate::constant::RAW_CARDS;\nuse crate::state::Card;\n\npub fn shuffle_cards() -> Vec<Card> {\n    let mut raw_cards = RAW_CARDS;\n\n    raw_cards.shuffle(&mut rng());\n\n    raw_cards\n        .iter()\n        .map(|&p| Card {\n            id: nanoid!(),\n            flipped: false,\n            name: p,\n        })\n        .collect()\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/main.rs",
    "content": "mod components;\nmod constant;\nmod helper;\nmod state;\n\nuse crate::components::app::App;\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/function_memory_game/src/state.rs",
    "content": "use std::rc::Rc;\n\nuse gloo::storage::{LocalStorage, Storage};\nuse serde::{Deserialize, Serialize};\nuse yew::prelude::*;\n\nuse crate::constant::{CardName, Status, KEY_BEST_SCORE};\nuse crate::helper::shuffle_cards;\n\n#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]\npub struct RawCard {\n    pub id: String,\n    pub name: CardName,\n}\n\n#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]\npub struct Card {\n    pub id: String,\n    pub flipped: bool,\n    pub name: CardName,\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]\npub struct State {\n    pub unresolved_card_pairs: u8,\n    pub best_score: u32, // seconds to solve\n    pub status: Status,\n    pub cards: Vec<Card>,\n    pub last_card: Option<RawCard>,\n    pub rollback_cards: Option<[RawCard; 2]>,\n}\n\nimpl PartialEq<RawCard> for &mut Card {\n    fn eq(&self, other: &RawCard) -> bool {\n        self.id == other.id && self.name == other.name\n    }\n}\n\npub enum Action {\n    FlipCard(RawCard),\n    RollbackCards([RawCard; 2]),\n    TrySaveBestScore(u32),\n    GameReset,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::FlipCard(card) => {\n                let status = if self.status == Status::Ready {\n                    Status::Playing\n                } else {\n                    self.status\n                };\n\n                let mut cards = self.cards.clone();\n                cards.iter_mut().filter(|c| c.eq(&card)).for_each(|c| {\n                    c.flipped = !c.flipped;\n                });\n\n                let last_card = self.last_card.clone();\n\n                match last_card {\n                    None => State {\n                        unresolved_card_pairs: self.unresolved_card_pairs,\n                        best_score: self.best_score,\n                        status,\n                        cards,\n                        last_card: Some(card),\n                        rollback_cards: None,\n                    },\n                    Some(last_card) => {\n                        let mut unresolved_card_pairs = self.unresolved_card_pairs;\n                        let mut status = self.status;\n                        let mut rollback_cards = self.rollback_cards.clone();\n                        if card.id.ne(&last_card.id) && card.name.eq(&last_card.name) {\n                            unresolved_card_pairs = self.unresolved_card_pairs - 1;\n                            status = if unresolved_card_pairs == 0 {\n                                Status::Passed\n                            } else {\n                                self.status\n                            };\n                        } else {\n                            rollback_cards = Some([last_card, card]);\n                        }\n\n                        State {\n                            unresolved_card_pairs,\n                            best_score: self.best_score,\n                            status,\n                            cards,\n                            last_card: None,\n                            rollback_cards,\n                        }\n                    }\n                }\n                .into()\n            }\n            Action::RollbackCards(rollback_cards) => {\n                let mut cards = self.cards.clone();\n\n                cards\n                    .iter_mut()\n                    .filter(|c| {\n                        rollback_cards.contains(\n                            &(RawCard {\n                                id: c.id.clone(),\n                                name: c.name,\n                            }),\n                        )\n                    })\n                    .for_each(|c| {\n                        c.flipped = !c.flipped;\n                    });\n\n                State {\n                    unresolved_card_pairs: self.unresolved_card_pairs,\n                    best_score: self.best_score,\n                    status: self.status,\n                    cards,\n                    last_card: self.last_card.clone(),\n                    rollback_cards: None,\n                }\n                .into()\n            }\n            Action::TrySaveBestScore(sec_past) => {\n                if sec_past < self.best_score {\n                    let _ = LocalStorage::set(KEY_BEST_SCORE, sec_past);\n                    State {\n                        best_score: sec_past,\n                        ..self.as_ref().clone()\n                    }\n                    .into()\n                } else {\n                    self // No update needed, return existing state\n                }\n            }\n            Action::GameReset => State::reset().into(),\n        }\n    }\n}\n\nimpl State {\n    pub fn reset() -> State {\n        State {\n            unresolved_card_pairs: 8,\n            best_score: LocalStorage::get(KEY_BEST_SCORE).unwrap_or(9999),\n            status: Status::Ready,\n            cards: shuffle_cards(),\n            last_card: None,\n            rollback_cards: None,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/function_router/Cargo.toml",
    "content": "[package]\nname = \"function_router\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nimage = { version = \"0.25\", default-features = false, features = [\"png\"] }\nlipsum = { version = \"0.9.1\", git = \"https://github.com/mgeisler/lipsum.git\", rev = \"233e48a\" }\nlog.workspace = true\nrand = { workspace = true, features = [\"small_rng\"] }\nyew = { path = \"../../packages/yew\" }\nyew-router = { path = \"../../packages/yew-router\" }\nserde = { workspace = true, features = [\"derive\"] }\ngloo.workspace = true\nwasm-logger.workspace = true\ninstant = { workspace = true }\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\ngetrandom = { workspace = true }\n\n[[bin]]\nname = \"function_router\"\nrequired-features = [\"yew/csr\"]\n"
  },
  {
    "path": "examples/function_router/README.md",
    "content": "# Function Router Example\n\nThis is identical to the router example, but written in function\ncomponents.\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffunction_router)](https://examples.yew.rs/function_router)\n\nA blog all about yew.\nThe best way to figure out what this example is about is to just open it up.\nIt's mobile friendly too!\n\n## Concepts\n\nThis example involves many different parts, here are just the Yew specific things:\n\n- Uses [`yew-router`] to render and switch between multiple pages.\n\nThe example automatically adapts to the `--public-url` value passed to Trunk.\nThis allows it to be hosted on any path, not just at the root.\nFor example, our demo is hosted at [/router](https://examples.yew.rs/router).\n\nThis is achieved by adding `<base data-trunk-public-url />` to the [index.html](index.html) file.\nTrunk rewrites this tag to contain the value passed to `--public-url` which can then be retrieved at runtime.\nTake a look at [`Route`](src/main.rs) for the implementation.\n\n## Improvements\n\n- Use a special image component which shows a progress bar until the image is loaded.\n- Scroll back to the top after switching route\n- Run content generation in a dedicated web worker\n- Use longer Markov chains to achieve more coherent results\n- Make images deterministic (the same seed should produce the same images)\n- Show posts by the author on their page\n  (this is currently impossible because we need to find post seeds which in turn generate the author's seed)\n- Show other posts at the end of a post (\"continue reading\")\n- Home (`/`) should include links to the post list and the author introduction\n- Detect sub-path from `--public-url` value passed to Trunk. See: thedodd/trunk#51\n\n[`yew-router`]: https://docs.rs/yew-router/latest/yew_router/\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```\n\n### Notes\n\nContent generation can take up quite a bit of time in debug builds. It may be better to run this example in release mode if it is slow."
  },
  {
    "path": "examples/function_router/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/function_router/data/keywords.txt",
    "content": "allergenics\narchaeology\naustria\nberries\nbirds\ncolor\nconservation\ncosmology\nculture\neurope\nevergreens\nfleshy\nfrance\nguides\nhorticulture\nireland\nlandscaping\nmedicine\nmusic\npoison\nreligion\nrome\nrust\nscotland\nseeds\nspain\ntaxonomy\ntoxics\ntradition\ntrees\nwasm\nwood\nwoodworking\nyew\n"
  },
  {
    "path": "examples/function_router/data/syllables.txt",
    "content": "ald\nber\nfe\nger\njo\njus\nkas\nlix\nlu\nmon\nmour\nnas\nridge\nry\nsi\nstar\ntey\ntim\ntin\nyew\n"
  },
  {
    "path": "examples/function_router/data/yew.txt",
    "content": "Taxonomy and naming\n\nThe word yew is from Proto-Germanic, possibly originally a loanword from Gaulish.\nIn German it is known as Eibe. Baccata is Latin for bearing berries.\nThe word yew as it was originally used seems to refer to the color brown.\nThe yew was known to Theophrastus, who noted its preference for mountain coolness and shade,\nits evergreen character and its slow growth.\n\nMost Romance languages, with the notable exception of French,\nkept a version of the Latin word taxus from the same root as toxic.\nIn Slavic languages, the same root is preserved.\n\nIn Iran, the tree is known as sorkhdār.\n\nThe common yew was one of the many species first described by Linnaeus.\nIt is one of around 30 conifer species in seven genera in the family Taxaceae, which is placed in the order Pinales.\n\n\nDescription\n\nIt is a small to medium-sized evergreen tree, growing 10 to 20 metres tall, with a trunk up to 2 metres in diameter.\nThe bark is thin, scaly brown, coming off in small flakes aligned with the stem.\nThe leaves are flat, dark green, 1 to 4 centimetres long and 2 to 3 millimetres broad, arranged spirally on the stem,\nbut with the leaf bases twisted to align the leaves in two flat rows either side of the stem,\nexcept on erect leading shoots where the spiral arrangement is more obvious.\nThe leaves are poisonous.\n\nThe seed cones are modified, each cone containing a single seed, which is 4 to 7 millimetres long,\nand partly surrounded by a fleshy scale which develops into a soft, bright red berry-like structure called an aril.\nThe aril is 8 to 15 millimetres long and wide and open at the end.\nThe arils mature 6 to 9 months after pollination, and with the seed contained,\nare eaten by thrushes, waxwings and other birds, which disperse the hard seeds undamaged in their droppings.\nMaturation of the arils is spread over 2 to 3 months, increasing the chances of successful seed dispersal.\nThe seeds themselves are poisonous and bitter, but are opened and eaten by some bird species including hawfinches,\ngreenfinches and great tits.\nThe aril is not poisonous, it is gelatinous and very sweet tasting. The male cones are globose,\n3–6 millimetres in diameter, and shed their pollen in early spring.\nThe yew is mostly dioecious, but occasional individuals can be variably monoecious, or change sex with time.\n\n\nLongevity\n\nTaxus baccata can reach 400 to 600 years of age.\nSome specimens live longer but the age of yews is often overestimated.\nTen yews in Britain are believed to predate the 10th century.\nThe potential age of yews is impossible to determine accurately and is subject to much dispute.\nThere is rarely any wood as old as the entire tree, while the boughs themselves often become hollow with age,\nmaking ring counts impossible.\nEvidence based on growth rates and archaeological work of surrounding structures suggests the oldest yews,\nsuch as the Fortingall Yew in Perthshire, Scotland, may be in the range of 2,000 years,\nplacing them among the oldest plants in Europe.\nOne characteristic contributing to yew's longevity is that it is able to split under the weight of advanced growth\nwithout succumbing to disease in the fracture, as do most other trees. Another is its ability to give rise to new\nepicormic and basal shoots from cut surfaces and low on its trunk, even at an old age.\n\n\nSignificant trees\n\nThe Fortingall Yew in Perthshire, Scotland,\nhas the largest recorded trunk girth in Britain and experts estimate it to be 2,000 to 3,000 years old,\nalthough it may be a remnant of a post-Roman Christian site and around 1,500 years old.\nThe Llangernyw Yew in Clwyd, Wales, can be found at an early saint site and is about 1,500 years old.\nOther well known yews include the Ankerwycke Yew, the Balderschwang Yew, the Caesarsboom, the Florence Court Yew,\nand the Borrowdale Fraternal Four, of which poet William Wordsworth wrote.\nThe Kingley Vale National Nature Reserve in West Sussex has one of Europe's largest yew woodlands.\n\nThe oldest specimen in Spain is located in Bermiego, Asturias. It is known as Teixu l'Iglesia in the Asturian language.\nIt stands 15m tall with a trunk diameter of 7m and a crown diameter of 15m.\nIt was declared a Natural Monument on April 27,\n1995 by the Asturian Government and is protected by the Plan of Natural Resources.\n\nA unique forest formed by Taxus baccata and European box lies within the city of Sochi, in the Western Caucasus.\n\nThe oldest Irish Yew, the Florence Court Yew, still stands in the grounds of Florence Court estate in County Fermanagh,\nNorthern Ireland.\nThe Irish Yew has become ubiquitous in cemeteries across the world and it is believed that all known examples are from\ncuttings from this tree.\n\n\nToxicity\n\nThe entire yew bush, except the aril, is poisonous.\nIt is toxic due to a group of chemicals called taxine alkaloids.\nTheir cardiotoxicity is well known and act via calcium and sodium channel antagonism, causing an increase in\ncytoplasmic calcium currents of the myocardial cells.\nThe seeds contain the highest concentrations of these alkaloids. If any leaves or seeds of the plant are ingested,\nurgent medical advice is recommended as well as observation for at least 6 hours after the point of ingestion.\nThe most cardiotoxic taxine is Taxine B followed by Taxine A.\nTaxine B also happens to be the most common alkaloid in the Taxus species.\n\nYew poisonings are relatively common in both domestic and wild animals who consume the plant accidentally,\nresulting in countless fatalities in livestock.\nThe taxine alkaloids are absorbed quickly from the intestine and in high enough quantities can cause death due to\ncardiac arrest or respiratory failure.\nTaxines are also absorbed efficiently via the skin and Taxus species should thus be handled with care and preferably\nwith gloves.\nTaxus baccata leaves contain approximately 5mg of taxines per 1g of leaves.\n\nThe estimated lethal dose of taxine alkaloids is approximately 3.0mg/kg body weight for humans.\nThe lethal dose for an adult is reported to be 50g of yew needles.\nPatients who ingest a lethal dose frequently die due to cardiogenic shock, in spite of resuscitation efforts.\nThere are currently no known antidotes for yew poisoning,\nbut drugs such as atropine have been used to treat the symptoms.\nTaxine remains in the plant all year, with maximal concentrations appearing during the winter.\nDried yew plant material retains its toxicity for several months and even increases its toxicity as the water is removed.\nFallen leaves should therefore also be considered toxic.\nPoisoning usually occurs when leaves of yew trees are eaten,\nbut in at least one case a victim inhaled sawdust from a yew tree.\n\nIt is difficult to measure taxine alkaloids and this is a major reason as to why different studies show different results.\n\nSeveral studies have found taxine LD50 values under 20mg/kg in mice and rats.\n\nMale and monoecious yews in this genus release toxic pollen, which can cause the mild symptoms.\nThe pollen is also a trigger for asthma.\nThese pollen grains are only 15 microns in size, and can easily pass through most window screens.\n\n\nAllergenic potential\n\nYews in this genus are primarily separate-sexed, and males are extremely allergenic,\nwith an OPALS allergy scale rating of 10 out of 10.\nCompletely female yews have an OPALS rating of 1, and are considered allergy-fighting.\nMale yews bloom and release abundant amounts of pollen in the spring;\ncompletely female yews only trap pollen while producing none.\n\n\nUses and traditions\n\nIn the ancient Celtic world, the yew tree had extraordinary importance; a passage by Caesar narrates that Cativolcus,\nchief of the Eburones poisoned himself with yew rather than submit to Rome.\nSimilarly, Florus notes that when the Cantabrians were under siege by the legate Gaius Furnius in 22 BC,\nmost of them took their lives either by the sword, by fire, or by a poison extracted ex arboribus taxeis, that is,\nfrom the yew tree.\nIn a similar way, Orosius notes that when the Astures were besieged at Mons Medullius,\nthey preferred to die by their own swords or by the yew tree poison rather than surrender.\n\nThe word York is derived from the Brittonic name Eburākon,\na combination of eburos \"yew-tree\" and a suffix of appurtenance meaning either \"place of the yew trees\";\nor alternatively, \"the settlement of Eburos\".\n\nThe name Eboracum became the Anglian Eoforwic in the 7th century.\nWhen the Danish army conquered the city in 866, its name became Jórvík.\n\nThe Old French and Norman name of the city following the Norman Conquest was recorded as Everwic in works such as\nWace's Roman de Rou.\nJórvík, meanwhile, gradually reduced to York in the centuries after the Conquest,\nmoving from the Middle English Yerk in the 14th century through Yourke in the 16th century to Yarke in the 17th century.\nThe form York was first recorded in the 13th century. Many company and place names, such as the Ebor race meeting,\nrefer to the Latinised Brittonic, Roman name.\n\nThe 12th‑century chronicler Geoffrey of Monmouth, in his fictional account of the prehistoric kings of Britain,\nHistoria Regum Britanniae, suggests the name derives from that of a pre-Roman city founded by the legendary king Ebraucus.\n\nThe Archbishop of York uses Ebor as his surname in his signature.\n\nThe area of Ydre in the South Swedish highlands is interpreted to mean place of yews.\nTwo localities in particular, Idhult and Idebo, appear to be further associated with yews.\n\n\nReligion\n\nThe yew is traditionally and regularly found in churchyards in England, Wales, Scotland, Ireland and Northern France.\nSome examples can be found in La Haye-de-Routot or La Lande-Patry.\nIt is said up to 40 people could stand inside one of the La-Haye-de-Routot yew trees,\nand the Le Ménil-Ciboult yew is probably the largest at 13m diameter.\nYews may grow to become exceptionally large and may live to be over 2,000 years old.\nSometimes monks planted yews in the middle of their cloister, as at Muckross Abbey or abbaye de Jumièges.\nSome ancient yew trees are located at St. Mary the Virgin Church, Overton-on-Dee in Wales.\n\nIn Asturian tradition and culture, the yew tree was considered to be linked with the land, people,\nancestors and ancient religion. It was tradition on All Saints' Day to bring a branch of a yew tree to the tombs of\nthose who had died recently so they would be guided in their return to the Land of Shadows.\nThe yew tree has been found near chapels,\nchurches and cemeteries since ancient times as a symbol of the transcendence of death.\nThey are often found in the main squares of villages where people celebrated the open councils that served as a way of\ngeneral assembly to rule village affairs.\n\nIt has been suggested that the sacred tree at the Temple at Uppsala was an ancient yew tree.\nThe Christian church commonly found it expedient to take over existing pre-Christian sacred sites for churches.\nIt has also been suggested that yews were planted at religious sites as their long life was suggestive of eternity,\nor because, being toxic when ingested, they were seen as trees of death.\nAnother suggested explanation is that yews were planted to discourage farmers and drovers from letting animals wander\nonto the burial grounds, the poisonous foliage being the disincentive.\nA further possible reason is that fronds and branches of yew were often used as a substitute for palms on Palm Sunday.\n\nSome yew trees were actually native to the sites before the churches were built.\nKing Edward I of England ordered yew trees to be planted in churchyards to offer some protection to the buildings.\nYews are poisonous so by planting them in the churchyards cattle that were not allowed to graze on hallowed\nground were safe from eating yew. Yew branches touching the ground take root and sprout again;\nthis became a symbol of death, rebirth and therefore immortality.\n\nIn interpretations of Norse cosmology, the tree Yggdrasil has traditionally been interpreted as a giant ash tree.\nSome scholars now believe errors were made in past interpretations of the ancient writings,\nand that the tree is most likely a European yew.\n\nIn the Crann Ogham—the variation on the ancient Irish Ogham alphabet which consists of a list of trees—yew\nis the last in the main list of 20 trees, primarily symbolizing death.\nThere are stories of people who have committed suicide by ingesting the foliage.\nAs the ancient Celts also believed in the transmigration of the soul,\nthere is in some cases a secondary meaning of the eternal soul that survives death to be reborn in a new form.\n\n\nMedical\n\nCertain compounds found in the bark of yew trees were discovered by Wall and Wani in 1967 to have efficacy as\nanti-cancer agents.\nThe precursors of the chemotherapy drug paclitaxel were later shown to be synthesized easily from extracts\nof the leaves of European yew, which is a much more renewable source than the bark of the Pacific yew from which\nthey were initially isolated.\nThis ended a point of conflict in the early 1990s; many environmentalists,\nincluding Al Gore, had opposed the destructive harvesting of Pacific yew for paclitaxel cancer treatments.\nDocetaxel can then be obtained by semi-synthetic conversion from the precursors.\n\n\nWoodworking and longbows\n\nWood from the yew is classified as a closed-pore softwood, similar to cedar and pine.\nEasy to work, yew is among the hardest of the softwoods; yet it possesses a remarkable elasticity,\nmaking it ideal for products that require springiness, such as bows.\nDue to all parts of the yew and its volatile oils being poisonous and cardiotoxic,\na mask should be worn if one comes in contact with sawdust from the wood.\n\nOne of the world's oldest surviving wooden artifacts is a Clactonian yew spear head, found in 1911 at Clacton-on-Sea,\nin Essex, UK. Known as the Clacton Spear, it is estimated to be over 400,000 years old.\n\nYew is also associated with Wales and England because of the longbow,\nan early weapon of war developed in northern Europe,\nand as the English longbow the basis for a medieval tactical system.\nThe oldest surviving yew longbow was found at Rotten Bottom in Dumfries and Galloway, Scotland.\nIt has been given a calibrated radiocarbon date of 4040 BC to 3640 BC and is on display in the National Museum of\nScotland. Yew is the wood of choice for longbow making;\nthe heartwood is always on the inside of the bow with the sapwood on the outside.\nThis makes most efficient use of their properties as heartwood is best in compression whilst\nsapwood is superior in tension.\nHowever, much yew is knotty and twisted, and therefore unsuitable for bowmaking;\nmost trunks do not give good staves and even in a good trunk much wood has to be discarded.\n\nThere was a tradition of planting yew trees in churchyards throughout Britain and Ireland, among other reasons,\nas a resource for bows. \nArdchattan Priory whose yew trees, according to other accounts,\nwere inspected by Robert the Bruce and cut to make at least some of the longbows used at the Battle of Bannockburn.\n\nThe trade of yew wood to England for longbows was so robust that it depleted the stocks of good-quality,\nmature yew over a vast area.\nThe first documented import of yew bowstaves to England was in 1294.\nIn 1423 the Polish king commanded protection of yews in order to cut exports,\nfacing nearly complete destruction of local yew stock. In 1470 compulsory archery practice was renewed, and hazel, ash,\nand laburnum were specifically allowed for practice bows.\nSupplies still proved insufficient, until by the Statute of Westminster in 1472,\nevery ship coming to an English port had to bring four bowstaves for every tun.\nRichard III of England increased this to ten for every tun. This stimulated a vast network of extraction and supply,\nwhich formed part of royal monopolies in southern Germany and Austria.\nIn 1483, the price of bowstaves rose from two to eight pounds per hundred,\nand in 1510 the Venetians would only sell a hundred for sixteen pounds.\nIn 1507 the Holy Roman Emperor asked the Duke of Bavaria to stop cutting yew, but the trade was profitable,\nand in 1532 the royal monopoly was granted for the usual quantity if there are that many.\nIn 1562, the Bavarian government sent a long plea to the Holy Roman Emperor asking him to stop the cutting of yew,\nand outlining the damage done to the forests by its selective extraction,\nwhich broke the canopy and allowed wind to destroy neighbouring trees. In 1568, despite a request from Saxony,\nno royal monopoly was granted because there was no yew to cut,\nand the next year Bavaria and Austria similarly failed to produce enough yew to justify a royal monopoly.\nForestry records in this area in the 17th century do not mention yew, and it seems that no mature trees were to be had.\nThe English tried to obtain supplies from the Baltic, but at this period bows were being replaced by guns in any case.\n\n\nHorticulture\n\nToday European yew is widely used in landscaping and ornamental horticulture.\nDue to its dense, dark green, mature foliage, and its tolerance of even very severe pruning,\nit is used especially for formal hedges and topiary.\nIts relatively slow growth rate means that in such situations it needs to be clipped only once per year.\n\nWell over 200 cultivars of T. baccata have been named. The most popular of these are the Irish yew,\na fastigiate cultivar of the European yew selected from two trees found growing in Ireland,\nand the several cultivars with yellow leaves, collectively known as golden yew. In some locations,\nwhen hemmed in by buildings or other trees,\nan Irish yew can reach 20 feet in height without exceeding 2 feet in diameter at its thickest point,\nalthough with age many Irish yews assume a fat cigar shape rather than being truly columnar.\n\nEuropean yew will tolerate growing in a wide range of soils and situations, including shallow chalk soils and shade,\nalthough in deep shade its foliage may be less dense.\nHowever it cannot tolerate waterlogging,\nand in poorly-draining situations is liable to succumb to the root-rotting pathogen Phytophthora cinnamomi.\n\nIn Europe, Taxus baccata grows naturally north to Molde in southern Norway, but it is used in gardens further north.\nIt is also popular as a bonsai in many parts of Europe and makes a handsome small- to large-sized bonsai.\n\n\nPrivies\n\nIn England, yew has historically been sometimes associated with privies,\npossibly because the smell of the plant keeps insects away.\n\n\nMusical instruments\n\nThe late Robert Lundberg, a noted luthier who performed extensive research on historical lute-making methodology,\nstates in his 2002 book Historical Lute Construction that yew was historically a prized wood for lute construction.\nEuropean legislation establishing use limits and requirements for yew limited supplies available to luthiers,\nbut it was apparently as prized among medieval, renaissance,\nand baroque lute builders as Brazilian rosewood is among contemporary guitar-makers for its quality of sound and beauty.\n\n\nConservation\n\nClippings from ancient specimens in the UK, including the Fortingall Yew,\nwere taken to the Royal Botanic Gardens in Edinburgh to form a mile-long hedge.\nThe purpose of this project is to maintain the DNA of Taxus baccata.\nThe species is threatened by felling, partly due to rising demand from pharmaceutical companies, and disease.\n\nAnother conservation programme was run in Catalonia in the early 2010s, by the Forest Sciences Centre of Catalonia,\nin order to protect genetically endemic yew populations, and preserve them from overgrazing and forest fires.\nIn the framework of this programme, the 4th International Yew Conference was organised in the Poblet Monastery in 2014,\nwhich proceedings are available.\n\nThere has also been a conservation programme in northern Portugal and Northern Spain.\n"
  },
  {
    "path": "examples/function_router/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>Yew • Function Router</title>\n    <base data-trunk-public-url />\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css\"\n    />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n    <link data-trunk rel=\"rust\" data-cargo-features=\"yew/csr\" data-bin=\"function_router\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/function_router/index.scss",
    "content": ".hero {\n  &.has-background {\n    position: relative;\n    overflow: hidden;\n  }\n\n  &-background {\n    position: absolute;\n    object-fit: cover;\n    object-position: bottom;\n    width: 100%;\n    height: 100%;\n\n    &.is-transparent {\n      opacity: 0.3;\n    }\n  }\n}\n\n.burger {\n  background-color: transparent;\n  border: none;\n}\n\n.navbar-brand {\n  align-items: center;\n}\n"
  },
  {
    "path": "examples/function_router/src/app.rs",
    "content": "use std::collections::HashMap;\n\nuse yew::prelude::*;\nuse yew_router::history::{AnyHistory, History, MemoryHistory};\nuse yew_router::prelude::*;\n\nuse crate::components::nav::Nav;\nuse crate::pages::author::Author;\nuse crate::pages::author_list::AuthorList;\nuse crate::pages::home::Home;\nuse crate::pages::page_not_found::PageNotFound;\nuse crate::pages::post::Post;\nuse crate::pages::post_list::PostList;\n\npub fn route_meta(route: &Route) -> (&'static str, &'static str) {\n    match route {\n        Route::Home => (\"Home\", \"The best yew content on the web\"),\n        Route::Posts => (\"Posts\", \"Browse all posts\"),\n        Route::Post { .. } => (\"Post\", \"Read a post\"),\n        Route::Authors => (\"Authors\", \"Meet the authors\"),\n        Route::Author { .. } => (\"Author\", \"Author profile\"),\n        Route::NotFound => (\"Not Found\", \"Page not found\"),\n    }\n}\n\n#[derive(Routable, PartialEq, Eq, Clone, Debug)]\npub enum Route {\n    #[at(\"/posts/:id\")]\n    Post { id: u32 },\n    #[at(\"/posts\")]\n    Posts,\n    #[at(\"/authors/:id\")]\n    Author { id: u32 },\n    #[at(\"/authors\")]\n    Authors,\n    #[at(\"/\")]\n    Home,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component]\npub fn App() -> Html {\n    html! {\n        <BrowserRouter>\n            <Nav />\n\n            <main>\n                <Switch<Route> render={switch} />\n            </main>\n            <footer class=\"footer\">\n                <div class=\"content has-text-centered\">\n                    { \"Powered by \" }\n                    <a href=\"https://yew.rs\">{ \"Yew\" }</a>\n                    { \" using \" }\n                    <a href=\"https://bulma.io\">{ \"Bulma\" }</a>\n                </div>\n            </footer>\n        </BrowserRouter>\n    }\n}\n\n#[derive(Properties, PartialEq, Eq, Debug)]\npub struct ServerAppProps {\n    pub url: AttrValue,\n    pub queries: HashMap<String, String>,\n}\n\n#[component]\npub fn ServerApp(props: &ServerAppProps) -> Html {\n    let history = AnyHistory::from(MemoryHistory::new());\n    history\n        .push_with_query(&*props.url, &props.queries)\n        .unwrap();\n\n    html! {\n        <Router history={history}>\n            <Nav />\n\n            <main>\n                <Switch<Route> render={switch} />\n            </main>\n            <footer class=\"footer\">\n                <div class=\"content has-text-centered\">\n                    { \"Powered by \" }\n                    <a href=\"https://yew.rs\">{ \"Yew\" }</a>\n                    { \" using \" }\n                    <a href=\"https://bulma.io\">{ \"Bulma\" }</a>\n                </div>\n            </footer>\n        </Router>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Post { id } => {\n            html! { <Post seed={id} /> }\n        }\n        Route::Posts => {\n            html! { <PostList /> }\n        }\n        Route::Author { id } => {\n            html! { <Author seed={id} /> }\n        }\n        Route::Authors => {\n            html! { <AuthorList /> }\n        }\n        Route::Home => {\n            html! { <Home /> }\n        }\n        Route::NotFound => {\n            html! { <PageNotFound /> }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/bin/function_router.rs",
    "content": "pub use function_router::*;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/function_router/src/components/author_card.rs",
    "content": "use std::rc::Rc;\n\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::content::Author;\nuse crate::generator::Generated;\nuse crate::Route;\n\n#[derive(Clone, Debug, PartialEq, Eq, Properties)]\npub struct Props {\n    pub seed: u32,\n}\n\n#[derive(PartialEq, Eq, Debug)]\npub struct AuthorState {\n    pub inner: Author,\n}\n\nimpl Reducible for AuthorState {\n    type Action = u32;\n\n    fn reduce(self: Rc<Self>, action: u32) -> Rc<Self> {\n        Self {\n            inner: Author::generate_from_seed(action),\n        }\n        .into()\n    }\n}\n\n#[function_component]\npub fn AuthorCard(props: &Props) -> Html {\n    let seed = props.seed;\n\n    let author = use_reducer_eq(|| AuthorState {\n        inner: Author::generate_from_seed(seed),\n    });\n\n    {\n        let author_dispatcher = author.dispatcher();\n        use_effect_with(seed, move |seed| {\n            author_dispatcher.dispatch(*seed);\n\n            || {}\n        });\n    }\n\n    let author = &author.inner;\n\n    html! {\n        <div class=\"card\">\n            <div class=\"card-content\">\n                <div class=\"media\">\n                    <div class=\"media-left\">\n                        <figure class=\"image is-128x128\">\n                            <img alt=\"Author's profile picture\" src={author.image_url.clone()} />\n                        </figure>\n                    </div>\n                    <div class=\"media-content\">\n                        <p class=\"title is-3\">{ &author.name }</p>\n                        <p>\n                            { \"I like \" }\n                            <b>{ author.keywords.join(\", \") }</b>\n                        </p>\n                    </div>\n                </div>\n            </div>\n            <footer class=\"card-footer\">\n                <Link<Route> classes={classes!(\"card-footer-item\")} to={Route::Author { id: author.seed }}>\n                    { \"Profile\" }\n                </Link<Route>>\n            </footer>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/components/mod.rs",
    "content": "pub mod author_card;\npub mod nav;\npub mod pagination;\npub mod post_card;\npub mod progress_delay;\n"
  },
  {
    "path": "examples/function_router/src/components/nav.rs",
    "content": "use yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::Route;\n\n#[function_component]\npub fn Nav() -> Html {\n    let navbar_active = use_state_eq(|| false);\n\n    let toggle_navbar = {\n        let navbar_active = navbar_active.clone();\n\n        Callback::from(move |_| {\n            navbar_active.set(!*navbar_active);\n        })\n    };\n\n    let active_class = if !*navbar_active { \"is-active\" } else { \"\" };\n\n    html! {\n        <nav class=\"navbar is-primary\" role=\"navigation\" aria-label=\"main navigation\">\n            <div class=\"navbar-brand\">\n                <h1 class=\"navbar-item is-size-3\">{ \"Yew Blog\" }</h1>\n\n                <button class={classes!(\"navbar-burger\", \"burger\", active_class)}\n                    aria-label=\"menu\" aria-expanded=\"false\"\n                    onclick={toggle_navbar}\n                >\n                    <span aria-hidden=\"true\"></span>\n                    <span aria-hidden=\"true\"></span>\n                    <span aria-hidden=\"true\"></span>\n                </button>\n            </div>\n            <div class={classes!(\"navbar-menu\", active_class)}>\n                <div class=\"navbar-start\">\n                    <Link<Route> classes={classes!(\"navbar-item\")} to={Route::Home}>\n                        { \"Home\" }\n                    </Link<Route>>\n                    <Link<Route> classes={classes!(\"navbar-item\")} to={Route::Posts}>\n                        { \"Posts\" }\n                    </Link<Route>>\n\n                    <div class=\"navbar-item has-dropdown is-hoverable\">\n                        <div class=\"navbar-link\">\n                            { \"More\" }\n                        </div>\n                        <div class=\"navbar-dropdown\">\n                            <Link<Route> classes={classes!(\"navbar-item\")} to={Route::Authors}>\n                                { \"Meet the authors\" }\n                            </Link<Route>>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </nav>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/components/pagination.rs",
    "content": "use std::ops::Range;\n\nuse serde::{Deserialize, Serialize};\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::Route;\n\nconst ELLIPSIS: &str = \"\\u{02026}\";\n\n#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]\npub struct PageQuery {\n    pub page: u32,\n}\n\n#[derive(Clone, Debug, PartialEq, Eq, Properties)]\npub struct Props {\n    pub page: u32,\n    pub total_pages: u32,\n    pub route_to_page: Route,\n}\n\n#[function_component]\npub fn RelNavButtons(props: &Props) -> Html {\n    let Props {\n        page,\n        total_pages,\n        route_to_page: to,\n    } = props.clone();\n\n    html! {\n        <>\n            <Link<Route, PageQuery>\n                classes={classes!(\"pagination-previous\")}\n                disabled={page==1}\n                query={Some(PageQuery{page: page - 1})}\n                to={to.clone()}\n            >\n                { \"Previous\" }\n            </Link<Route, PageQuery>>\n            <Link<Route, PageQuery>\n                classes={classes!(\"pagination-next\")}\n                disabled={page==total_pages}\n                query={Some(PageQuery{page: page + 1})}\n                {to}\n            >\n                { \"Next page\" }\n            </Link<Route, PageQuery>>\n        </>\n    }\n}\n\n#[derive(Properties, Clone, Debug, PartialEq, Eq)]\npub struct RenderLinksProps {\n    range: Range<u32>,\n    len: usize,\n    max_links: usize,\n    props: Props,\n}\n\n#[function_component]\npub fn RenderLinks(props: &RenderLinksProps) -> Html {\n    let RenderLinksProps {\n        range,\n        len,\n        max_links,\n        props,\n    } = props.clone();\n\n    let mut range = range;\n\n    if len > max_links {\n        let last_link =\n            html! {<RenderLink to_page={range.next_back().unwrap()} props={props.clone()} />};\n        // remove 1 for the ellipsis and 1 for the last link\n        let links = range\n            .take(max_links - 2)\n            .map(|page| html! {<RenderLink to_page={page} props={props.clone()} />});\n        html! {\n            <>\n                { for links }\n                <li><span class=\"pagination-ellipsis\">{ ELLIPSIS }</span></li>\n                { last_link }\n            </>\n        }\n    } else {\n        html! {\n            for page in range {\n                <RenderLink to_page={page} props={props.clone()} />\n            }\n        }\n    }\n}\n\n#[derive(Properties, Clone, Debug, PartialEq, Eq)]\npub struct RenderLinkProps {\n    to_page: u32,\n    props: Props,\n}\n\n#[function_component]\npub fn RenderLink(props: &RenderLinkProps) -> Html {\n    let RenderLinkProps { to_page, props } = props.clone();\n\n    let Props {\n        page,\n        route_to_page,\n        ..\n    } = props;\n\n    let is_current_class = if to_page == page { \"is-current\" } else { \"\" };\n\n    html! {\n        <li>\n            <Link<Route, PageQuery>\n                classes={classes!(\"pagination-link\", is_current_class)}\n                to={route_to_page}\n                query={Some(PageQuery{page: to_page})}\n            >\n                { to_page }\n            </Link<Route, PageQuery>>\n        </li>\n    }\n}\n\n#[function_component]\npub fn Links(props: &Props) -> Html {\n    const LINKS_PER_SIDE: usize = 3;\n\n    let Props {\n        page, total_pages, ..\n    } = *props;\n\n    let pages_prev = page.saturating_sub(1) as usize;\n    let pages_next = (total_pages - page) as usize;\n\n    let links_left = LINKS_PER_SIDE.min(pages_prev)\n            // if there are less than `LINKS_PER_SIDE` to the right, we add some more on the left.\n            + LINKS_PER_SIDE.saturating_sub(pages_next);\n    let links_right = 2 * LINKS_PER_SIDE - links_left;\n\n    html! {\n        <>\n            <RenderLinks range={ 1..page } len={pages_prev} max_links={links_left} props={props.clone()} />\n            <RenderLink to_page={page} props={props.clone()} />\n            <RenderLinks range={ page + 1..total_pages + 1 } len={pages_next} max_links={links_right} props={props.clone()} />\n        </>\n    }\n}\n\n#[function_component]\npub fn Pagination(props: &Props) -> Html {\n    html! {\n        <nav class=\"pagination is-right\" role=\"navigation\" aria-label=\"pagination\">\n            <RelNavButtons ..{props.clone()} />\n            <ul class=\"pagination-list\">\n                <Links ..{props.clone()} />\n            </ul>\n        </nav>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/components/post_card.rs",
    "content": "use std::rc::Rc;\n\nuse yew::prelude::*;\nuse yew_router::components::Link;\n\nuse crate::content::PostMeta;\nuse crate::generator::Generated;\nuse crate::Route;\n\n#[derive(Clone, Debug, PartialEq, Eq, Properties)]\npub struct Props {\n    pub seed: u32,\n}\n\n#[derive(PartialEq, Eq, Debug)]\npub struct PostMetaState {\n    inner: PostMeta,\n}\n\nimpl Reducible for PostMetaState {\n    type Action = u32;\n\n    fn reduce(self: Rc<Self>, action: u32) -> Rc<Self> {\n        Self {\n            inner: PostMeta::generate_from_seed(action),\n        }\n        .into()\n    }\n}\n\n#[function_component]\npub fn PostCard(props: &Props) -> Html {\n    let seed = props.seed;\n\n    let post = use_reducer_eq(|| PostMetaState {\n        inner: PostMeta::generate_from_seed(seed),\n    });\n\n    {\n        let post_dispatcher = post.dispatcher();\n        use_effect_with(seed, move |seed| {\n            post_dispatcher.dispatch(*seed);\n\n            || {}\n        });\n    }\n\n    let post = &post.inner;\n\n    html! {\n        <div class=\"card\">\n            <div class=\"card-image\">\n                <figure class=\"image is-2by1\">\n                    <img alt=\"This post's image\" src={post.image_url.clone()} loading=\"lazy\" />\n                </figure>\n            </div>\n            <div class=\"card-content\">\n                <Link<Route> classes={classes!(\"title\", \"is-block\")} to={Route::Post { id: post.seed }}>\n                    { &post.title }\n                </Link<Route>>\n                <Link<Route> classes={classes!(\"subtitle\", \"is-block\")} to={Route::Author { id: post.author.seed }}>\n                    { &post.author.name }\n                </Link<Route>>\n            </div>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/components/progress_delay.rs",
    "content": "use std::rc::Rc;\n\nuse gloo::timers::callback::Interval;\nuse instant::Instant;\nuse yew::prelude::*;\n\nconst RESOLUTION: u32 = 500;\nconst MIN_INTERVAL_MS: u32 = 50;\n\npub enum ValueAction {\n    Tick,\n    Props(Props),\n}\n\n#[derive(Clone, PartialEq, Debug)]\npub struct ValueState {\n    start: Instant,\n\n    value: f64,\n\n    props: Props,\n}\n\nimpl Reducible for ValueState {\n    type Action = ValueAction;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Self::Action::Props(props) => Self {\n                start: self.start,\n                value: self.value,\n                props,\n            }\n            .into(),\n\n            Self::Action::Tick => {\n                let elapsed = self.start.elapsed().as_millis() as u32;\n                let value = elapsed as f64 / self.props.duration_ms as f64;\n\n                let mut start = self.start;\n\n                if elapsed > self.props.duration_ms {\n                    self.props.on_complete.emit(());\n                    start = Instant::now();\n                } else {\n                    self.props.on_progress.emit(self.value);\n                }\n\n                Self {\n                    start,\n                    value,\n                    props: self.props.clone(),\n                }\n                .into()\n            }\n        }\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Properties)]\npub struct Props {\n    pub duration_ms: u32,\n    pub on_complete: Callback<()>,\n    #[prop_or_default]\n    pub on_progress: Callback<f64>,\n}\n\n#[function_component]\npub fn ProgressDelay(props: &Props) -> Html {\n    let Props { duration_ms, .. } = props.clone();\n\n    let value = {\n        let props = props.clone();\n        use_reducer(move || ValueState {\n            start: Instant::now(),\n            value: 0.0,\n\n            props,\n        })\n    };\n\n    {\n        let value = value.clone();\n        use_effect_with((), move |_| {\n            let interval = (duration_ms / RESOLUTION).min(MIN_INTERVAL_MS);\n            let interval = Interval::new(interval, move || value.dispatch(ValueAction::Tick));\n\n            || {\n                let _interval = interval;\n            }\n        });\n    }\n\n    {\n        let value = value.clone();\n        use_effect_with(props.clone(), move |props| {\n            value.dispatch(ValueAction::Props(props.clone()));\n            || {}\n        });\n    }\n\n    let value = &value.value;\n\n    html! {\n        <progress class=\"progress is-primary\" value={value.to_string()} max=1.0>\n            { format!(\"{:.0}%\", 100.0 * value) }\n        </progress>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/content.rs",
    "content": "use crate::generator::{Generated, Generator};\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Author {\n    pub seed: u32,\n    pub name: String,\n    pub keywords: Vec<String>,\n    pub image_url: String,\n}\n\nimpl Generated for Author {\n    fn generate(gen: &mut Generator) -> Self {\n        let name = gen.human_name();\n        let keywords = gen.keywords();\n        let image_url = gen.face_image_url((150, 150));\n        Self {\n            seed: gen.seed,\n            name,\n            keywords,\n            image_url,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct PostMeta {\n    pub seed: u32,\n    pub title: String,\n    pub author: Author,\n    pub keywords: Vec<String>,\n    pub image_url: String,\n}\n\nimpl Generated for PostMeta {\n    fn generate(gen: &mut Generator) -> Self {\n        let title = gen.title();\n        let author = Author::generate_from_seed(gen.new_seed());\n        let keywords = gen.keywords();\n        let image_url = gen.image_url((300, 150), &keywords);\n\n        Self {\n            seed: gen.seed,\n            title,\n            author,\n            keywords,\n            image_url,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Post {\n    pub meta: PostMeta,\n    pub content: Vec<PostPart>,\n}\n\nimpl Generated for Post {\n    fn generate(gen: &mut Generator) -> Self {\n        const PARTS_MIN: u32 = 1;\n        const PARTS_MAX: u32 = 10;\n\n        let meta = PostMeta::generate(gen);\n\n        let n_parts = gen.range(PARTS_MIN, PARTS_MAX);\n        let content = (0..n_parts).map(|_| PostPart::generate(gen)).collect();\n\n        Self { meta, content }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub enum PostPart {\n    Section(Section),\n    Quote(Quote),\n}\n\nimpl Generated for PostPart {\n    fn generate(gen: &mut Generator) -> Self {\n        // Because we pass the same (already used) generator down,\n        // the resulting `Section` and `Quote` aren't be reproducible with just the seed.\n        // This doesn't matter here though, because we don't need it.\n        if gen.chance(1, 10) {\n            Self::Quote(Quote::generate(gen))\n        } else {\n            Self::Section(Section::generate(gen))\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Section {\n    pub title: String,\n    pub paragraphs: Vec<String>,\n    pub image_url: String,\n}\n\nimpl Generated for Section {\n    fn generate(gen: &mut Generator) -> Self {\n        const PARAGRAPHS_MIN: u32 = 1;\n        const PARAGRAPHS_MAX: u32 = 8;\n\n        let title = gen.title();\n        let n_paragraphs = gen.range(PARAGRAPHS_MIN, PARAGRAPHS_MAX);\n        let paragraphs = (0..n_paragraphs).map(|_| gen.paragraph()).collect();\n        let image_url = gen.image_url((200, 100), &[]);\n\n        Self {\n            title,\n            paragraphs,\n            image_url,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Quote {\n    pub author: Author,\n    pub content: String,\n}\n\nimpl Generated for Quote {\n    fn generate(gen: &mut Generator) -> Self {\n        // wouldn't it be funny if the author ended up quoting themselves?\n        let author = Author::generate_from_seed(gen.new_seed());\n        let content = gen.paragraph();\n        Self { author, content }\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/generator.rs",
    "content": "use std::sync::LazyLock;\n\nuse lipsum::MarkovChain;\nuse rand::distr::Bernoulli;\nuse rand::rngs::StdRng;\nuse rand::seq::IteratorRandom;\nuse rand::{Rng, SeedableRng};\n\nconst KEYWORDS: &str = include_str!(\"../data/keywords.txt\");\nconst SYLLABLES: &str = include_str!(\"../data/syllables.txt\");\nconst YEW_CONTENT: &str = include_str!(\"../data/yew.txt\");\n\nstatic YEW_CHAIN: LazyLock<MarkovChain<'static>> = LazyLock::new(|| {\n    let mut chain = MarkovChain::new();\n    chain.learn(YEW_CONTENT);\n    chain\n});\n\npub struct Generator {\n    pub seed: u32,\n    rng: StdRng,\n}\nimpl Generator {\n    pub fn from_seed(seed: u32) -> Self {\n        let rng = StdRng::seed_from_u64(seed as u64);\n\n        Self { seed, rng }\n    }\n}\nimpl Generator {\n    pub fn new_seed(&mut self) -> u32 {\n        self.rng.random()\n    }\n\n    /// [low, high)\n    pub fn range(&mut self, low: u32, high: u32) -> u32 {\n        self.rng.random_range(low..high)\n    }\n\n    /// `n / d` chance\n    pub fn chance(&mut self, n: u32, d: u32) -> bool {\n        self.rng.sample(Bernoulli::from_ratio(n, d).unwrap())\n    }\n\n    pub fn image_url(&mut self, dimension: (u32, u32), _keywords: &[String]) -> String {\n        let seed: u32 = self.rng.random();\n        let (width, height) = dimension;\n        crate::imagegen::generate_data_url(width, height, seed)\n    }\n\n    pub fn face_image_url(&mut self, dimension: (u32, u32)) -> String {\n        let seed: u32 = self.rng.random();\n        let (width, height) = dimension;\n        crate::imagegen::generate_data_url(width, height, seed)\n    }\n\n    pub fn human_name(&mut self) -> String {\n        const SYLLABLES_MIN: u32 = 1;\n        const SYLLABLES_MAX: u32 = 5;\n\n        let n_syllables = self.rng.random_range(SYLLABLES_MIN..SYLLABLES_MAX);\n        let first_name = SYLLABLES\n            .split_whitespace()\n            .choose_multiple(&mut self.rng, n_syllables as usize)\n            .join(\"\");\n\n        let n_syllables = self.rng.random_range(SYLLABLES_MIN..SYLLABLES_MAX);\n        let last_name = SYLLABLES\n            .split_whitespace()\n            .choose_multiple(&mut self.rng, n_syllables as usize)\n            .join(\"\");\n\n        format!(\"{} {}\", title_case(&first_name), title_case(&last_name))\n    }\n\n    pub fn keywords(&mut self) -> Vec<String> {\n        const KEYWORDS_MIN: u32 = 1;\n        const KEYWORDS_MAX: u32 = 4;\n\n        let n_keywords = self.rng.random_range(KEYWORDS_MIN..KEYWORDS_MAX);\n        KEYWORDS\n            .split_whitespace()\n            .map(ToOwned::to_owned)\n            .choose_multiple(&mut self.rng, n_keywords as usize)\n    }\n\n    pub fn title(&mut self) -> String {\n        const WORDS_MIN: u32 = 3;\n        const WORDS_MAX: u32 = 8;\n        const SMALL_WORD_LEN: u32 = 3;\n\n        let n_words = self.rng.random_range(WORDS_MIN..WORDS_MAX);\n\n        let mut title = String::new();\n\n        let words = YEW_CHAIN\n            .iter(&mut self.rng, None)\n            .map(|word: &str| word.trim_matches(|c: char| c.is_ascii_punctuation()))\n            .filter(|word| !word.is_empty())\n            .take(n_words as usize);\n\n        for (i, word) in words.enumerate() {\n            if i > 0 {\n                title.push(' ');\n            }\n\n            // Capitalize the first word and all long words.\n            if i == 0 || word.len() > SMALL_WORD_LEN as usize {\n                title.push_str(&title_case(word));\n            } else {\n                title.push_str(word);\n            }\n        }\n        title\n    }\n\n    pub fn sentence(&mut self) -> String {\n        const WORDS_MIN: u32 = 7;\n        const WORDS_MAX: u32 = 25;\n\n        let n_words = self.rng.random_range(WORDS_MIN..WORDS_MAX);\n        join_words(YEW_CHAIN.iter(&mut self.rng, None).take(n_words as usize))\n    }\n\n    pub fn paragraph(&mut self) -> String {\n        const SENTENCES_MIN: u32 = 3;\n        const SENTENCES_MAX: u32 = 20;\n\n        let n_sentences = self.rng.random_range(SENTENCES_MIN..SENTENCES_MAX);\n        let mut paragraph = String::new();\n        for i in 0..n_sentences {\n            if i > 0 {\n                paragraph.push(' ');\n            }\n\n            paragraph.push_str(&self.sentence());\n        }\n        paragraph\n    }\n}\n\nfn join_words<'a>(words: impl Iterator<Item = &'a str>) -> String {\n    let mut result = String::new();\n    for (i, word) in words.enumerate() {\n        if i > 0 {\n            result.push(' ');\n        }\n        if i == 0 {\n            result.push_str(&title_case(word));\n        } else {\n            result.push_str(word);\n        }\n    }\n    if !result.is_empty() && !result.ends_with(|c: char| c.is_ascii_punctuation()) {\n        result.push('.');\n    }\n    result\n}\n\nfn title_case(word: &str) -> String {\n    let idx = match word.chars().next() {\n        Some(c) => c.len_utf8(),\n        None => 0,\n    };\n\n    let mut result = String::with_capacity(word.len());\n    result.push_str(&word[..idx].to_uppercase());\n    result.push_str(&word[idx..]);\n    result\n}\n\npub trait Generated: Sized {\n    fn generate(gen: &mut Generator) -> Self;\n    fn generate_from_seed(seed: u32) -> Self {\n        Self::generate(&mut Generator::from_seed(seed))\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/imagegen.rs",
    "content": "use std::collections::HashMap;\nuse std::io::Cursor;\nuse std::sync::{LazyLock, Mutex};\n\nuse image::{ImageBuffer, Rgb};\n\ntype ImageCache = Mutex<HashMap<(u32, u32, u32), String>>;\n\nstatic CACHE: LazyLock<ImageCache> = LazyLock::new(|| Mutex::new(HashMap::new()));\n\n// Cosine palette (Inigo Quilez style)\n// color(t) = a + b * cos(2pi(c*t + d))\nstruct Palette {\n    a: [f64; 3],\n    b: [f64; 3],\n    c: [f64; 3],\n    d: [f64; 3],\n}\n\nconst PALETTES: &[Palette] = &[\n    // sunset\n    Palette {\n        a: [0.5, 0.5, 0.5],\n        b: [0.5, 0.5, 0.5],\n        c: [1.0, 1.0, 1.0],\n        d: [0.00, 0.33, 0.67],\n    },\n    // electric\n    Palette {\n        a: [0.5, 0.5, 0.5],\n        b: [0.5, 0.5, 0.5],\n        c: [1.0, 1.0, 0.5],\n        d: [0.80, 0.90, 0.30],\n    },\n    // forest\n    Palette {\n        a: [0.5, 0.5, 0.5],\n        b: [0.5, 0.5, 0.5],\n        c: [2.0, 1.0, 0.0],\n        d: [0.50, 0.20, 0.25],\n    },\n    // candy\n    Palette {\n        a: [0.8, 0.5, 0.4],\n        b: [0.2, 0.4, 0.2],\n        c: [2.0, 1.0, 1.0],\n        d: [0.00, 0.25, 0.25],\n    },\n    // ocean\n    Palette {\n        a: [0.0, 0.5, 0.5],\n        b: [0.0, 0.5, 0.5],\n        c: [0.0, 0.5, 0.3],\n        d: [0.0, 0.0, 0.2],\n    },\n];\n\nfn palette_color(pal: &Palette, t: f64) -> [u8; 3] {\n    let tau = std::f64::consts::TAU;\n    let mut rgb = [0u8; 3];\n    for (i, channel) in rgb.iter_mut().enumerate() {\n        let v = pal.a[i] + pal.b[i] * (tau * (pal.c[i] * t + pal.d[i])).cos();\n        *channel = (v.clamp(0.0, 1.0) * 255.0) as u8;\n    }\n    rgb\n}\n\nfn hash(mut x: i32, mut y: i32, seed: u32) -> u32 {\n    let mut h = seed;\n    x = x.wrapping_mul(374761393);\n    y = y.wrapping_mul(668265263);\n    h = h.wrapping_add(x as u32).wrapping_mul(2654435761);\n    h = h.wrapping_add(y as u32).wrapping_mul(2246822519);\n    h ^= h >> 13;\n    h = h.wrapping_mul(3266489917);\n    h ^= h >> 16;\n    h\n}\n\nfn grad(hash: u32, dx: f64, dy: f64) -> f64 {\n    match hash & 3 {\n        0 => dx + dy,\n        1 => -dx + dy,\n        2 => dx - dy,\n        _ => -dx - dy,\n    }\n}\n\nfn lerp(a: f64, b: f64, t: f64) -> f64 {\n    a + t * (b - a)\n}\n\nfn fade(t: f64) -> f64 {\n    t * t * t * (t * (t * 6.0 - 15.0) + 10.0)\n}\n\nfn noise2d(x: f64, y: f64, seed: u32) -> f64 {\n    let xi = x.floor() as i32;\n    let yi = y.floor() as i32;\n    let xf = x - x.floor();\n    let yf = y - y.floor();\n    let u = fade(xf);\n    let v = fade(yf);\n\n    let n00 = grad(hash(xi, yi, seed), xf, yf);\n    let n10 = grad(hash(xi + 1, yi, seed), xf - 1.0, yf);\n    let n01 = grad(hash(xi, yi + 1, seed), xf, yf - 1.0);\n    let n11 = grad(hash(xi + 1, yi + 1, seed), xf - 1.0, yf - 1.0);\n\n    lerp(lerp(n00, n10, u), lerp(n01, n11, u), v)\n}\n\nfn fbm(x: f64, y: f64, seed: u32, octaves: u32) -> f64 {\n    let mut value = 0.0;\n    let mut amp = 0.5;\n    let mut freq = 1.0;\n    for _ in 0..octaves {\n        value += amp * noise2d(x * freq, y * freq, seed);\n        freq *= 2.0;\n        amp *= 0.5;\n    }\n    value\n}\n\nfn warped_fbm(x: f64, y: f64, seed: u32, warp: f64, octaves: u32) -> f64 {\n    let qx = fbm(x, y, seed, octaves);\n    let qy = fbm(x + 5.2, y + 1.3, seed.wrapping_add(1), octaves);\n\n    fbm(x + warp * qx, y + warp * qy, seed.wrapping_add(2), octaves)\n}\n\n/// Generate a procedural image as an `ImageBuffer` with the given dimensions and seed.\n/// The seed selects the color palette and drives the noise pattern.\npub fn generate_image(width: u32, height: u32, seed: u32) -> ImageBuffer<Rgb<u8>, Vec<u8>> {\n    let pal_idx = (seed as usize) % PALETTES.len();\n    let pal = &PALETTES[pal_idx];\n\n    let scale = 3.5;\n    let warp = 2.0;\n    let octaves = 3;\n\n    ImageBuffer::from_fn(width, height, |px, py| {\n        let x = (px as f64 / width as f64) * scale;\n        let y = (py as f64 / height as f64) * scale;\n\n        let v = warped_fbm(x, y, seed, warp, octaves);\n        let t = (v * 0.5 + 0.5).clamp(0.0, 1.0);\n        let [r, g, b] = palette_color(pal, t);\n        Rgb([r, g, b])\n    })\n}\n\n/// Generate a procedural image and return it as PNG bytes.\npub fn generate_png(width: u32, height: u32, seed: u32) -> Vec<u8> {\n    let img = generate_image(width, height, seed);\n    let mut bytes: Vec<u8> = Vec::new();\n    img.write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)\n        .expect(\"PNG encoding failed\");\n    bytes\n}\n\n/// Generate a procedural image and return it as a base64 `data:` URI suitable for `<img src=...>`.\n/// Results are cached — repeated calls with the same arguments are free.\npub fn generate_data_url(width: u32, height: u32, seed: u32) -> String {\n    let key = (width, height, seed);\n    if let Some(cached) = CACHE.lock().unwrap().get(&key) {\n        return cached.clone();\n    }\n\n    use image::codecs::png::{CompressionType, FilterType, PngEncoder};\n    use image::ImageEncoder;\n\n    let img = generate_image(width, height, seed);\n    let mut bytes: Vec<u8> = Vec::new();\n    let encoder = PngEncoder::new_with_quality(\n        Cursor::new(&mut bytes),\n        CompressionType::Fast,\n        FilterType::Sub,\n    );\n    encoder\n        .write_image(img.as_raw(), width, height, image::ExtendedColorType::Rgb8)\n        .expect(\"PNG encoding failed\");\n\n    let b64 = base64_encode(&bytes);\n    let url = format!(\"data:image/png;base64,{b64}\");\n    CACHE.lock().unwrap().insert(key, url.clone());\n    url\n}\n\nfn base64_encode(data: &[u8]) -> String {\n    const CHARS: &[u8] = b\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n    let mut result = String::with_capacity(data.len().div_ceil(3) * 4);\n    for chunk in data.chunks(3) {\n        let b0 = chunk[0] as u32;\n        let b1 = if chunk.len() > 1 { chunk[1] as u32 } else { 0 };\n        let b2 = if chunk.len() > 2 { chunk[2] as u32 } else { 0 };\n        let triple = (b0 << 16) | (b1 << 8) | b2;\n        result.push(CHARS[((triple >> 18) & 0x3F) as usize] as char);\n        result.push(CHARS[((triple >> 12) & 0x3F) as usize] as char);\n        if chunk.len() > 1 {\n            result.push(CHARS[((triple >> 6) & 0x3F) as usize] as char);\n        } else {\n            result.push('=');\n        }\n        if chunk.len() > 2 {\n            result.push(CHARS[(triple & 0x3F) as usize] as char);\n        } else {\n            result.push('=');\n        }\n    }\n    result\n}\n"
  },
  {
    "path": "examples/function_router/src/lib.rs",
    "content": "// # Implementation Note:\n//\n// This example is also used to demonstrate SSR hydration.\n// It is important to follow the following rules when updating this example:\n//\n// - Do not use usize for randomised contents.\n//\n//   usize differs in memory size in 32-bit and 64-bit targets (wasm32 is a 32-bit target family.)\n//   and would lead to a different value even if the Rng at the same state.\n//\n// - Do not swap StdRng for SmallRng.\n//\n//   SmallRng uses different algorithms depending on the platform.\n//   Hence, it may not yield the same value on the client and server side.\n\nmod app;\nmod components;\nmod content;\nmod generator;\npub mod imagegen;\nmod pages;\n\npub use app::*;\npub use content::*;\npub use generator::*;\n"
  },
  {
    "path": "examples/function_router/src/pages/author.rs",
    "content": "use yew::prelude::*;\n\nuse crate::components::author_card::AuthorState;\nuse crate::content;\nuse crate::generator::Generated;\n\n#[derive(Clone, Debug, Eq, PartialEq, Properties)]\npub struct Props {\n    pub seed: u32,\n}\n\n#[function_component]\npub fn Author(props: &Props) -> Html {\n    let seed = props.seed;\n\n    let author = use_reducer_eq(|| AuthorState {\n        inner: content::Author::generate_from_seed(seed),\n    });\n\n    {\n        let author_dispatcher = author.dispatcher();\n        use_effect_with(seed, move |seed| {\n            author_dispatcher.dispatch(*seed);\n\n            || {}\n        });\n    }\n\n    let author = &author.inner;\n\n    html! {\n        <div class=\"section container\">\n            <div class=\"tile is-ancestor is-vertical\">\n                <div class=\"tile is-parent\">\n                    <article class=\"tile is-child notification is-light\">\n                        <p class=\"title\">{ &author.name }</p>\n                    </article>\n                </div>\n                <div class=\"tile\">\n                    <div class=\"tile is-parent is-3\">\n                        <article class=\"tile is-child notification\">\n                            <p class=\"title\">{ \"Interests\" }</p>\n                            <div class=\"tags\">\n                                { for author.keywords.iter().map(|tag| html! { <span class=\"tag is-info\">{ tag }</span> }) }\n                            </div>\n                        </article>\n                    </div>\n                    <div class=\"tile is-parent\">\n                        <figure class=\"tile is-child image is-square\">\n                            <img alt=\"The author's profile picture.\" src={author.image_url.clone()} />\n                        </figure>\n                    </div>\n                    <div class=\"tile is-parent\">\n                        <article class=\"tile is-child notification is-info\">\n                            <div class=\"content\">\n                                <p class=\"title\">{ \"About me\" }</p>\n                                <div class=\"content\">\n                                    { \"This author has chosen not to reveal anything about themselves\" }\n                                </div>\n                            </div>\n                        </article>\n                    </div>\n                </div>\n            </div>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/pages/author_list.rs",
    "content": "use rand::{distr, Rng};\nuse yew::prelude::*;\n\nuse crate::components::author_card::AuthorCard;\nuse crate::components::progress_delay::ProgressDelay;\n\n/// Amount of milliseconds to wait before showing the next set of authors.\nconst CAROUSEL_DELAY_MS: u32 = 15000;\n\n#[function_component]\npub fn AuthorList() -> Html {\n    let seeds = use_state(random_author_seeds);\n\n    let authors = seeds.iter().map(|&seed| {\n        html! {\n            <div class=\"tile is-parent\">\n                <div class=\"tile is-child\">\n                    <AuthorCard {seed} />\n                </div>\n            </div>\n        }\n    });\n\n    let on_complete = {\n        let seeds = seeds.clone();\n\n        Callback::from(move |_| {\n            seeds.set(random_author_seeds());\n        })\n    };\n\n    html! {\n        <div class=\"container\">\n            <section class=\"hero\">\n                <div class=\"hero-body\">\n                    <div class=\"container\">\n                        <h1 class=\"title\">{ \"Authors\" }</h1>\n                        <h2 class=\"subtitle\">\n                            { \"Meet the definitely real people behind your favourite Yew content\" }\n                        </h2>\n                    </div>\n                </div>\n            </section>\n            <p class=\"section py-0\">\n                { \"It wouldn't be fair \" }\n                <i>{ \"(or possible :P)\" }</i>\n                {\" to list each and every author in alphabetical order.\"}\n                <br />\n                { \"So instead we chose to put more focus on the individuals by introducing you to two people at a time\" }\n            </p>\n            <div class=\"section\">\n                <div class=\"tile is-ancestor\">\n                    { for authors }\n                </div>\n                <ProgressDelay duration_ms={CAROUSEL_DELAY_MS} on_complete={on_complete} />\n            </div>\n        </div>\n    }\n}\n\nfn random_author_seeds() -> Vec<u32> {\n    rand::rng()\n        .sample_iter(distr::StandardUniform)\n        .take(2)\n        .collect()\n}\n"
  },
  {
    "path": "examples/function_router/src/pages/home.rs",
    "content": "use yew::prelude::*;\n\n#[function_component]\nfn InfoTiles() -> Html {\n    html! {\n        <>\n            <div class=\"tile is-parent\">\n                <div class=\"tile is-child box\">\n                    <p class=\"title\">{ \"What are yews?\" }</p>\n                    <p class=\"subtitle\">{ \"Everything you need to know!\" }</p>\n\n                    <div class=\"content\">\n                        {r#\"\n                            A yew is a small to medium-sized evergreen tree, growing 10 to 20 metres tall, with a trunk up to 2 metres in diameter.\n                            The bark is thin, scaly brown, coming off in small flakes aligned with the stem.\n                            The leaves are flat, dark green, 1 to 4 centimetres long and 2 to 3 millimetres broad, arranged spirally on the stem,\n                            but with the leaf bases twisted to align the leaves in two flat rows either side of the stem,\n                            except on erect leading shoots where the spiral arrangement is more obvious.\n                            The leaves are poisonous.\n                            \"#}\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"tile is-parent\">\n                <div class=\"tile is-child box\">\n                    <p class=\"title\">{ \"Who are we?\" }</p>\n\n                    <div class=\"content\">\n                        { \"We're a small team of just 2\" }\n                        <sup>{ 64 }</sup>\n                        { \" members working tirelessly to bring you the low-effort yew content we all desperately crave.\" }\n                        <br />\n                        {r#\"\n                                We put a ton of effort into fact-checking our posts.\n                                Some say they read like a Wikipedia article - what a compliment!\n                            \"#}\n                    </div>\n                </div>\n            </div>\n        </>\n    }\n}\n\n#[function_component]\npub fn Home() -> Html {\n    html! {\n        <div class=\"tile is-ancestor is-vertical\">\n            <div class=\"tile is-child hero\">\n                <div class=\"hero-body container pb-0\">\n                    <h1 class=\"title is-1\">{ \"Welcome...\" }</h1>\n                    <h2 class=\"subtitle\">{ \"...to the best yew content\" }</h2>\n                </div>\n            </div>\n\n            <div class=\"tile is-child\">\n                <figure class=\"image is-3by1\">\n                    <img alt=\"A procedurally generated decorative image.\" src={crate::imagegen::generate_data_url(600, 200, 42)} />\n                </figure>\n            </div>\n\n            <div class=\"tile is-parent container\">\n                <InfoTiles />\n            </div>\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/pages/mod.rs",
    "content": "pub mod author;\npub mod author_list;\npub mod home;\npub mod page_not_found;\npub mod post;\npub mod post_list;\n"
  },
  {
    "path": "examples/function_router/src/pages/page_not_found.rs",
    "content": "use yew::prelude::*;\n\n#[function_component]\npub fn PageNotFound() -> Html {\n    html! {\n        <section class=\"hero is-danger is-bold is-large\">\n            <div class=\"hero-body\">\n                <div class=\"container\">\n                    <h1 class=\"title\">\n                        { \"Page not found\" }\n                    </h1>\n                    <h2 class=\"subtitle\">\n                        { \"Page page does not seem to exist\" }\n                    </h2>\n                </div>\n            </div>\n        </section>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/pages/post.rs",
    "content": "use std::rc::Rc;\n\nuse content::PostPart;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::generator::Generated;\nuse crate::{content, Route};\n\n#[derive(Clone, Debug, Eq, PartialEq, Properties)]\npub struct Props {\n    pub seed: u32,\n}\n\n#[derive(PartialEq, Eq, Debug)]\npub struct PostState {\n    pub inner: content::Post,\n}\n\nimpl Reducible for PostState {\n    type Action = u32;\n\n    fn reduce(self: Rc<Self>, action: u32) -> Rc<Self> {\n        Self {\n            inner: content::Post::generate_from_seed(action),\n        }\n        .into()\n    }\n}\n\n#[function_component]\npub fn Post(props: &Props) -> Html {\n    let seed = props.seed;\n\n    let post = use_reducer(|| PostState {\n        inner: content::Post::generate_from_seed(seed),\n    });\n\n    {\n        let post_dispatcher = post.dispatcher();\n        use_effect_with(seed, move |seed| {\n            post_dispatcher.dispatch(*seed);\n\n            || {}\n        });\n    }\n\n    let post = &post.inner;\n\n    let render_quote = |quote: &content::Quote| {\n        html! {\n            <article class=\"media block box my-6\">\n                <figure class=\"media-left\">\n                    <p class=\"image is-64x64\">\n                        <img alt=\"The author's profile\" src={quote.author.image_url.clone()} loading=\"lazy\" />\n                    </p>\n                </figure>\n                <div class=\"media-content\">\n                    <div class=\"content\">\n                        <Link<Route> classes={classes!(\"is-size-5\")} to={Route::Author { id: quote.author.seed }}>\n                            <strong>{ &quote.author.name }</strong>\n                        </Link<Route>>\n                        <p class=\"is-family-secondary\">\n                            { &quote.content }\n                        </p>\n                    </div>\n                </div>\n            </article>\n        }\n    };\n\n    let render_section_hero = |section: &content::Section| {\n        html! {\n            <section class=\"hero is-dark has-background mt-6 mb-3\">\n                <img alt=\"This section's image\" class=\"hero-background is-transparent\" src={section.image_url.clone()} loading=\"lazy\" />\n                <div class=\"hero-body\">\n                    <div class=\"container\">\n                        <h2 class=\"subtitle\">{ &section.title }</h2>\n                    </div>\n                </div>\n            </section>\n        }\n    };\n\n    let render_section = |section, show_hero| {\n        let hero = if show_hero {\n            render_section_hero(section)\n        } else {\n            html! {}\n        };\n        let paragraphs = section.paragraphs.iter().map(|paragraph| {\n            html! {\n                <p>{ paragraph }</p>\n            }\n        });\n        html! {\n            <section>\n                { hero }\n                <div>{ for paragraphs }</div>\n            </section>\n        }\n    };\n\n    let view_content = {\n        // don't show hero for the first section\n        let mut show_hero = false;\n\n        let parts = post.content.iter().map(|part| match part {\n            PostPart::Section(section) => {\n                let html = render_section(section, show_hero);\n                // show hero between sections\n                show_hero = true;\n                html\n            }\n            PostPart::Quote(quote) => {\n                // don't show hero after a quote\n                show_hero = false;\n                render_quote(quote)\n            }\n        });\n        html! {{for parts}}\n    };\n\n    let keywords = post\n        .meta\n        .keywords\n        .iter()\n        .map(|keyword| html! { <span class=\"tag is-info\">{ keyword }</span> });\n\n    html! {\n        <>\n            <section class=\"hero is-medium is-light has-background\">\n                <img alt=\"The hero's background\" class=\"hero-background is-transparent\" src={post.meta.image_url.clone()} />\n                <div class=\"hero-body\">\n                    <div class=\"container\">\n                        <h1 class=\"title\">\n                            { &post.meta.title }\n                        </h1>\n                        <h2 class=\"subtitle\">\n                            { \"by \" }\n                            <Link<Route> classes={classes!(\"has-text-weight-semibold\")} to={Route::Author { id: post.meta.author.seed }}>\n                                { &post.meta.author.name }\n                            </Link<Route>>\n                        </h2>\n                        <div class=\"tags\">\n                            { for keywords }\n                        </div>\n                    </div>\n                </div>\n            </section>\n            <div class=\"section container\">\n                { view_content }\n            </div>\n        </>\n    }\n}\n"
  },
  {
    "path": "examples/function_router/src/pages/post_list.rs",
    "content": "use yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::components::pagination::{PageQuery, Pagination};\nuse crate::components::post_card::PostCard;\nuse crate::Route;\n\nconst ITEMS_PER_PAGE: u32 = 10;\nconst TOTAL_PAGES: u32 = u32::MAX / ITEMS_PER_PAGE;\n\n#[function_component]\npub fn PostList() -> Html {\n    let location = use_location().unwrap();\n    let current_page = location.query::<PageQuery>().map(|it| it.page).unwrap_or(1);\n\n    let posts = {\n        let start_seed = (current_page - 1) * ITEMS_PER_PAGE;\n        let mut cards = (0..ITEMS_PER_PAGE).map(|seed_offset| {\n            html! {\n                <li class=\"list-item mb-5\">\n                    <PostCard seed={start_seed + seed_offset} />\n                </li>\n            }\n        });\n        html! {\n            <div class=\"columns\">\n                <div class=\"column\">\n                    <ul class=\"list\">\n                        { for cards.by_ref().take(ITEMS_PER_PAGE as usize / 2) }\n                    </ul>\n                </div>\n                <div class=\"column\">\n                    <ul class=\"list\">\n                        { for cards }\n                    </ul>\n                </div>\n            </div>\n        }\n    };\n\n    html! {\n        <div class=\"section container\">\n            <h1 class=\"title\">{ \"Posts\" }</h1>\n            <h2 class=\"subtitle\">{ \"All of our quality writing in one place\" }</h2>\n            { posts }\n            <Pagination\n                page={current_page}\n                total_pages={TOTAL_PAGES}\n                route_to_page={Route::Posts}\n            />\n        </div>\n    }\n}\n"
  },
  {
    "path": "examples/function_todomvc/Cargo.toml",
    "content": "[package]\nname = \"function_todomvc\"\nversion = \"0.1.0\"\nauthors = [\"Drew Hutton <drew.hutton@pm.me>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nserde = { workspace = true, features = [\"derive\"] }\nstrum.workspace = true\nstrum_macros.workspace = true\ngloo.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n\t\"HtmlInputElement\",\n]\n"
  },
  {
    "path": "examples/function_todomvc/README.md",
    "content": "# TodoMVC Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffunction_todomvc)](https://examples.yew.rs/function_todomvc)\n\nThis is an implementation of [TodoMVC](http://todomvc.com/) for Yew using function components and hooks.\n\n## Concepts\n\n- Uses [`function_components`](https://yew.rs/docs/next/concepts/function-components/introduction)\n- Uses [`gloo_storage`](https://docs.rs/gloo-storage/latest/gloo_storage/) to persist the state\n\n## Improvements\n\n- Use `yew-router` for the hash based routing\n- Clean up the code\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/function_todomvc/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/function_todomvc/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>Yew • Function TodoMVC</title>\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.css\"\n    />\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/todomvc-app-css@2.3.0/index.css\"\n    />\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/function_todomvc/src/components/entry.rs",
    "content": "use web_sys::{HtmlInputElement, MouseEvent};\nuse yew::events::{Event, FocusEvent, KeyboardEvent};\nuse yew::prelude::*;\n\nuse crate::hooks::use_bool_toggle::use_bool_toggle;\nuse crate::state::Entry as Item;\n\n#[derive(PartialEq, Properties, Clone)]\npub struct EntryProps {\n    pub entry: Item,\n    pub ontoggle: Callback<usize>,\n    pub onremove: Callback<usize>,\n    pub onedit: Callback<(usize, String)>,\n}\n\n#[function_component(Entry)]\npub fn entry(props: &EntryProps) -> Html {\n    let id = props.entry.id;\n    let mut class = Classes::from(\"todo\");\n\n    // We use the `use_bool_toggle` hook and set the default value to `false`\n    // as the default we are not editing the entry. When we want to edit the\n    // entry we can call the toggle method on the `UseBoolToggleHandle`\n    // which will trigger a re-render with the toggle value being `true` for that\n    // render and after that render the value of toggle will be flipped back to\n    // its default (`false`).\n    // We are relying on the behavior of `onblur` and `onkeypress` to cause\n    // another render so that this component will render again with the\n    // default value of toggle.\n    let edit_toggle = use_bool_toggle(false);\n    let is_editing = *edit_toggle;\n\n    if is_editing {\n        class.push(\"editing\");\n    }\n\n    if props.entry.completed {\n        class.push(\"completed\");\n    }\n\n    let ontoggle = {\n        let ontoggle = props.ontoggle.clone();\n        move |_| ontoggle.emit(id)\n    };\n\n    let onremove = {\n        let onremove = props.onremove.clone();\n        move |_| onremove.emit(id)\n    };\n\n    let onedit = {\n        let onedit = props.onedit.clone();\n        let edit_toggle = edit_toggle.clone();\n        move |value| {\n            edit_toggle.clone().toggle();\n            onedit.emit(value)\n        }\n    };\n\n    html! {\n        <li {class}>\n            <div class=\"view\">\n                <input\n                    type=\"checkbox\"\n                    class=\"toggle\"\n                    checked={props.entry.completed}\n                    onclick={ontoggle}\n                />\n                <label ondblclick={move |_| edit_toggle.clone().toggle()}>\n                    { &props.entry.description }\n                </label>\n                <button class=\"destroy\" onclick={onremove} />\n            </div>\n            <EntryEdit entry={props.entry.clone()} onedit={onedit} editing={is_editing} />\n        </li>\n    }\n}\n\n#[derive(PartialEq, Properties, Clone)]\npub struct EntryEditProps {\n    pub entry: Item,\n    pub onedit: Callback<(usize, String)>,\n    pub editing: bool,\n}\n\n#[function_component(EntryEdit)]\npub fn entry_edit(props: &EntryEditProps) -> Html {\n    if props.editing {\n        let id = props.entry.id;\n\n        let target_input_value = |e: &Event| {\n            let input: HtmlInputElement = e.target_unchecked_into();\n            input.value()\n        };\n\n        let onblur = {\n            let edit = props.onedit.clone();\n\n            move |e: FocusEvent| {\n                let value = target_input_value(&e);\n                edit.emit((id, value))\n            }\n        };\n\n        let onkeypress = {\n            let edit = props.onedit.clone();\n\n            move |e: KeyboardEvent| {\n                if e.key() == \"Enter\" {\n                    let value = target_input_value(&e);\n                    edit.emit((id, value))\n                }\n            }\n        };\n\n        let onmouseover = |e: MouseEvent| {\n            e.target_unchecked_into::<HtmlInputElement>()\n                .focus()\n                .unwrap_or_default();\n        };\n\n        html! {\n            <input\n                class=\"edit\"\n                type=\"text\"\n                value={props.entry.description.clone()}\n                {onmouseover}\n                {onblur}\n                {onkeypress}\n            />\n        }\n    } else {\n        html! { <input type=\"hidden\" /> }\n    }\n}\n"
  },
  {
    "path": "examples/function_todomvc/src/components/filter.rs",
    "content": "use yew::prelude::*;\n\nuse crate::state::Filter as FilterEnum;\n\n#[derive(PartialEq, Properties)]\npub struct FilterProps {\n    pub filter: FilterEnum,\n    pub selected: bool,\n    pub onset_filter: Callback<FilterEnum>,\n}\n\n#[function_component]\npub fn Filter(props: &FilterProps) -> Html {\n    let filter = props.filter;\n\n    let cls = if props.selected {\n        \"selected\"\n    } else {\n        \"not-selected\"\n    };\n\n    let onset_filter = {\n        let onset_filter = props.onset_filter.clone();\n        move |_| onset_filter.emit(filter)\n    };\n\n    html! {\n        <li>\n            <a class={cls}\n               href={props.filter.as_href()}\n               onclick={onset_filter}\n            >\n                { props.filter }\n            </a>\n        </li>\n    }\n}\n"
  },
  {
    "path": "examples/function_todomvc/src/components/header_input.rs",
    "content": "use web_sys::HtmlInputElement;\nuse yew::events::KeyboardEvent;\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties, Clone)]\npub struct HeaderInputProps {\n    pub onadd: Callback<String>,\n}\n\n#[function_component(HeaderInput)]\npub fn header_input(props: &HeaderInputProps) -> Html {\n    let onkeypress = {\n        let onadd = props.onadd.clone();\n\n        move |e: KeyboardEvent| {\n            if e.key() == \"Enter\" {\n                let input: HtmlInputElement = e.target_unchecked_into();\n                let value = input.value();\n\n                input.set_value(\"\");\n                onadd.emit(value);\n            }\n        }\n    };\n\n    html! {\n        <input\n            class=\"new-todo\"\n            placeholder=\"What needs to be done?\"\n            {onkeypress}\n        />\n    }\n}\n"
  },
  {
    "path": "examples/function_todomvc/src/components/info_footer.rs",
    "content": "use yew::prelude::*;\n\n#[function_component(InfoFooter)]\npub fn info_footer() -> Html {\n    html! {\n        <footer class=\"info\">\n            <p>{ \"Double-click to edit a todo\" }</p>\n            <p>{ \"Written by \" }<a href=\"https://github.com/Yoroshikun/\" target=\"_blank\">{ \"Drew Hutton <Yoroshi>\" }</a></p>\n            <p>{ \"Part of \" }<a href=\"http://todomvc.com/\" target=\"_blank\">{ \"TodoMVC\" }</a></p>\n        </footer>\n    }\n}\n"
  },
  {
    "path": "examples/function_todomvc/src/components.rs",
    "content": "pub mod entry;\npub mod filter;\npub mod header_input;\npub mod info_footer;\n"
  },
  {
    "path": "examples/function_todomvc/src/hooks/use_bool_toggle.rs",
    "content": "use std::ops::Deref;\nuse std::rc::Rc;\n\nuse yew::prelude::*;\n\n#[derive(Clone)]\npub struct UseBoolToggleHandle {\n    value: UseStateHandle<bool>,\n    toggle: Rc<dyn Fn()>,\n}\n\nimpl UseBoolToggleHandle {\n    pub fn toggle(self) {\n        (self.toggle)()\n    }\n}\n\nimpl Deref for UseBoolToggleHandle {\n    type Target = bool;\n\n    fn deref(&self) -> &Self::Target {\n        &self.value\n    }\n}\n\n/// This hook can be used to cause a re-render with the non-default value, which is\n/// then reset to the default value after that render.\n///\n/// # Arguments\n///\n/// * `default` - The default value.\n///\n/// # Example\n/// ```\n/// use crate::hooks::use_bool_toggle::use_bool_toggle;\n/// ...\n/// let value = use_bool_toggle(false);\n/// ...\n/// let onclick = {\n///     let value = value.clone();\n///     move |_| {\n///         value.toggle();\n///         // This will toggle the value to true.\n///         // Then render.\n///         // Post render it will toggle back to false skipping the render.\n///     }\n/// }\n/// <button {onclick}>{ \"Click me\" }</button>\n/// ...\n/// ```\n#[hook]\npub fn use_bool_toggle(default: bool) -> UseBoolToggleHandle {\n    let state = use_state_eq(|| default);\n\n    let toggle = {\n        let state = state.clone();\n        Rc::new(move || state.set(!*state))\n    };\n\n    UseBoolToggleHandle {\n        value: state,\n        toggle,\n    }\n}\n"
  },
  {
    "path": "examples/function_todomvc/src/hooks.rs",
    "content": "pub mod use_bool_toggle;\n"
  },
  {
    "path": "examples/function_todomvc/src/main.rs",
    "content": "use gloo::storage::{LocalStorage, Storage};\nuse state::{Action, Filter, State};\nuse strum::IntoEnumIterator;\nuse yew::prelude::*;\n\nmod components;\nmod hooks;\nmod state;\n\nuse components::entry::Entry as EntryItem;\nuse components::filter::Filter as FilterItem;\nuse components::header_input::HeaderInput;\nuse components::info_footer::InfoFooter;\n\nconst KEY: &str = \"yew.functiontodomvc.self\";\n\n#[function_component(App)]\nfn app() -> Html {\n    let state = use_reducer(|| State {\n        entries: LocalStorage::get(KEY).unwrap_or_else(|_| vec![]),\n        filter: Filter::All, // TODO: get from uri\n    });\n\n    // Effect\n    use_effect_with(state.clone(), |state| {\n        LocalStorage::set(KEY, &state.clone().entries).expect(\"failed to set\");\n    });\n\n    // Callbacks\n    fn make_callback<E, F>(state: &UseReducerHandle<State>, f: F) -> Callback<E>\n    where\n        F: Fn(E) -> Action + 'static,\n    {\n        let state = state.clone();\n        Callback::from(move |e: E| state.dispatch(f(e)))\n    }\n\n    let onremove = make_callback(&state, Action::Remove);\n    let ontoggle = make_callback(&state, Action::Toggle);\n    let ontoggle_all = make_callback(&state, |_| Action::ToggleAll);\n    let onclear_completed = make_callback(&state, |_| Action::ClearCompleted);\n    let onedit = make_callback(&state, Action::Edit);\n    let onadd = make_callback(&state, Action::Add);\n    let onset_filter = make_callback(&state, Action::SetFilter);\n\n    // Helpers\n    let completed = state\n        .entries\n        .iter()\n        .filter(|entry| Filter::Completed.fits(entry))\n        .count();\n\n    let is_all_completed = state\n        .entries\n        .iter()\n        .all(|e| state.filter.fits(e) & e.completed);\n\n    let total = state.entries.len();\n\n    let hidden_class = if state.entries.is_empty() {\n        \"hidden\"\n    } else {\n        \"\"\n    };\n\n    html! {\n        <div class=\"todomvc-wrapper\">\n            <section class=\"todoapp\">\n                <header class=\"header\">\n                    <h1>{ \"todos\" }</h1>\n                    <HeaderInput {onadd} />\n                </header>\n                <section class={classes!(\"main\", hidden_class)}>\n                    <input\n                        type=\"checkbox\"\n                        class=\"toggle-all\"\n                        id=\"toggle-all\"\n                        checked={is_all_completed}\n                        onclick={ontoggle_all}\n                    />\n                    <label for=\"toggle-all\" />\n                    <ul class=\"todo-list\">\n                        { for state.entries.iter().filter(|e| state.filter.fits(e)).cloned().map(|entry|\n                            html! {\n                                <EntryItem {entry}\n                                    ontoggle={&ontoggle}\n                                    onremove={&onremove}\n                                    onedit={&onedit}\n                                />\n                        }) }\n                    </ul>\n                </section>\n                <footer class={classes!(\"footer\", hidden_class)}>\n                    <span class=\"todo-count\">\n                        <strong>{ total }</strong>\n                        { \" item(s) left\" }\n                    </span>\n                    <ul class=\"filters\">\n                        { for Filter::iter().map(|filter| {\n                            html! {\n                                <FilterItem {filter}\n                                    selected={state.filter == filter}\n                                    onset_filter={&onset_filter}\n                                />\n                            }\n                        }) }\n                    </ul>\n                    <button class=\"clear-completed\" onclick={onclear_completed}>\n                        { format!(\"Clear completed ({completed})\") }\n                    </button>\n                </footer>\n            </section>\n            <InfoFooter />\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/function_todomvc/src/state.rs",
    "content": "use std::rc::Rc;\n\nuse serde::{Deserialize, Serialize};\nuse strum_macros::{Display, EnumIter};\nuse yew::html::IntoPropValue;\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]\npub struct State {\n    pub entries: Vec<Entry>,\n    pub filter: Filter,\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]\npub struct Entry {\n    pub id: usize,\n    pub description: String,\n    pub completed: bool,\n}\n\n#[derive(Clone, Copy, Debug, EnumIter, Display, PartialEq, Eq, Serialize, Deserialize)]\npub enum Filter {\n    All,\n    Active,\n    Completed,\n}\n\nimpl Filter {\n    pub fn fits(&self, entry: &Entry) -> bool {\n        match *self {\n            Filter::All => true,\n            Filter::Active => !entry.completed,\n            Filter::Completed => entry.completed,\n        }\n    }\n\n    pub fn as_href(&self) -> &'static str {\n        match self {\n            Filter::All => \"#/\",\n            Filter::Active => \"#/active\",\n            Filter::Completed => \"#/completed\",\n        }\n    }\n}\n\nimpl IntoPropValue<Html> for Filter {\n    fn into_prop_value(self) -> Html {\n        html! {<>{self.to_string()}</>}\n    }\n}\n\npub enum Action {\n    Add(String),\n    Edit((usize, String)),\n    Remove(usize),\n    SetFilter(Filter),\n    ToggleAll,\n    Toggle(usize),\n    ClearCompleted,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Add(description) => {\n                let mut entries = self.entries.clone();\n                entries.push(Entry {\n                    id: entries.last().map(|entry| entry.id + 1).unwrap_or(1),\n                    description,\n                    completed: false,\n                });\n                State {\n                    entries,\n                    filter: self.filter,\n                }\n                .into()\n            }\n            Action::Remove(id) => {\n                let mut entries = self.entries.clone();\n                entries.retain(|entry| entry.id != id);\n                State {\n                    entries,\n                    filter: self.filter,\n                }\n                .into()\n            }\n            Action::Toggle(id) => {\n                let mut entries = self.entries.clone();\n                let entry = entries.iter_mut().find(|entry| entry.id == id);\n                if let Some(entry) = entry {\n                    entry.completed = !entry.completed;\n                }\n                State {\n                    entries,\n                    filter: self.filter,\n                }\n                .into()\n            }\n            Action::Edit((id, description)) => {\n                let mut entries = self.entries.clone();\n\n                if description.is_empty() {\n                    entries.retain(|entry| entry.id != id)\n                }\n\n                let entry = entries.iter_mut().find(|entry| entry.id == id);\n                if let Some(entry) = entry {\n                    entry.description = description;\n                }\n                State {\n                    entries,\n                    filter: self.filter,\n                }\n                .into()\n            }\n            Action::ToggleAll => {\n                let mut entries = self.entries.clone();\n                for entry in &mut entries {\n                    if self.filter.fits(entry) {\n                        entry.completed = !entry.completed;\n                    }\n                }\n                State {\n                    entries,\n                    filter: self.filter,\n                }\n                .into()\n            }\n            Action::ClearCompleted => {\n                let mut entries = self.entries.clone();\n                entries.retain(|e| Filter::Active.fits(e));\n                State {\n                    entries,\n                    filter: self.filter,\n                }\n                .into()\n            }\n            Action::SetFilter(filter) => State {\n                filter,\n                entries: self.entries.clone(),\n            }\n            .into(),\n        }\n    }\n}\n"
  },
  {
    "path": "examples/futures/Cargo.toml",
    "content": "[package]\nname = \"futures\"\nversion = \"0.1.0\"\nauthors = [\"Henry Zimmerman <zimhen7@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\npulldown-cmark = { version = \"0.13\", default-features = false }\nwasm-bindgen.workspace = true\nwasm-bindgen-futures.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n  \"Headers\",\n  \"Request\",\n  \"RequestInit\",\n  \"RequestMode\",\n  \"Response\",\n  \"Window\",\n]\n"
  },
  {
    "path": "examples/futures/README.md",
    "content": "# Futures Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ffutures)](https://examples.yew.rs/futures)\n\nFetches Yew's README file and renders it to the page.\n\n## Concepts\n\nThis example shows off how to make asynchronous fetch requests using `web-sys` and Yew's futures support.\nIt makes use of yewtil's [`LinkFuture`] to easily send messages asynchronously.\nIt also contains a Markdown renderer which manually creates `Html` without using the `html!` macro.\n\n## Improvements\n\n- Markdown rendering code should be cleaned up.\n- Should make use of CSS to style the output.\n- This example could use a better name.\n- Since this features a Markdown renderer it should be possible to render more than just one document.\n\n[`linkfuture`]: https://docs.rs/yewtil/latest/yewtil/future/trait.LinkFuture.html\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/futures/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/futures/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Futures</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/futures/src/main.rs",
    "content": "use std::error::Error;\nuse std::fmt::{self, Debug, Display, Formatter};\n\nuse wasm_bindgen::prelude::*;\nuse wasm_bindgen::JsCast;\nuse wasm_bindgen_futures::JsFuture;\nuse web_sys::{Request, RequestInit, RequestMode, Response};\nuse yew::{html, Component, Context, Html};\n\nmod markdown;\n\nconst MARKDOWN_URL: &str = \"https://raw.githubusercontent.com/yewstack/yew/master/README.md\";\nconst INCORRECT_URL: &str = \"https://raw.githubusercontent.com/yewstack/yew/master/README.md.404\";\n\n/// Something wrong has occurred while fetching an external resource.\n#[derive(Debug, Clone, PartialEq)]\npub struct FetchError {\n    err: JsValue,\n}\nimpl Display for FetchError {\n    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n        Debug::fmt(&self.err, f)\n    }\n}\nimpl Error for FetchError {}\n\nimpl From<JsValue> for FetchError {\n    fn from(value: JsValue) -> Self {\n        Self { err: value }\n    }\n}\n\n/// The possible states a fetch request can be in.\npub enum FetchState<T> {\n    NotFetching,\n    Fetching,\n    Success(T),\n    Failed(FetchError),\n}\n\n/// Fetches markdown from Yew's README.md.\n///\n/// Consult the following for an example of the fetch api by the team behind web_sys:\n/// https://wasm-bindgen.github.io/wasm-bindgen/examples/fetch.html\nasync fn fetch_markdown(url: &'static str) -> Result<String, FetchError> {\n    let opts = RequestInit::new();\n    opts.set_method(\"GET\");\n    opts.set_mode(RequestMode::Cors);\n\n    let request = Request::new_with_str_and_init(url, &opts)?;\n\n    let window = gloo::utils::window();\n    let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;\n    let resp: Response = resp_value.dyn_into().unwrap();\n\n    let text = JsFuture::from(resp.text()?).await?;\n    Ok(text.as_string().unwrap())\n}\n\nenum Msg {\n    SetMarkdownFetchState(FetchState<String>),\n    GetMarkdown,\n    GetError,\n}\nstruct App {\n    markdown: FetchState<String>,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            markdown: FetchState::NotFetching,\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetMarkdownFetchState(fetch_state) => {\n                self.markdown = fetch_state;\n                true\n            }\n            Msg::GetMarkdown => {\n                ctx.link().send_future(async {\n                    match fetch_markdown(MARKDOWN_URL).await {\n                        Ok(md) => Msg::SetMarkdownFetchState(FetchState::Success(md)),\n                        Err(err) => Msg::SetMarkdownFetchState(FetchState::Failed(err)),\n                    }\n                });\n                ctx.link()\n                    .send_message(Msg::SetMarkdownFetchState(FetchState::Fetching));\n                false\n            }\n            Msg::GetError => {\n                ctx.link().send_future(async {\n                    match fetch_markdown(INCORRECT_URL).await {\n                        Ok(md) => Msg::SetMarkdownFetchState(FetchState::Success(md)),\n                        Err(err) => Msg::SetMarkdownFetchState(FetchState::Failed(err)),\n                    }\n                });\n                ctx.link()\n                    .send_message(Msg::SetMarkdownFetchState(FetchState::Fetching));\n                false\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        match &self.markdown {\n            FetchState::NotFetching => html! {\n                <>\n                    <button onclick={ctx.link().callback(|_| Msg::GetMarkdown)}>\n                        { \"Get Markdown\" }\n                    </button>\n                    <button onclick={ctx.link().callback(|_| Msg::GetError)}>\n                        { \"Get using incorrect URL\" }\n                    </button>\n                </>\n            },\n            FetchState::Fetching => html! { \"Fetching\" },\n            FetchState::Success(data) => html! { markdown::render_markdown(data) },\n            FetchState::Failed(err) => html! { err },\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/futures/src/markdown.rs",
    "content": "/// Original author of this code is [Nathan Ringo](https://github.com/remexre)\n/// Source: https://github.com/acmumn/mentoring/blob/master/web-client/src/view/markdown.rs\nuse pulldown_cmark::{Alignment, CodeBlockKind, Event, Options, Parser, Tag, TagEnd};\nuse yew::virtual_dom::{VNode, VTag, VText};\nuse yew::Html;\n\nstruct TableContext {\n    next_cell_index: usize,\n    in_head: bool,\n    has_body: bool,\n    alignment: Vec<Alignment>,\n}\n\nstruct TagWriter {\n    root_children: Vec<VNode>,\n    spine: Vec<VTag>,\n    table_ctx: Option<TableContext>,\n}\n\nimpl TagWriter {\n    fn new() -> Self {\n        Self {\n            root_children: vec![],\n            spine: vec![],\n            table_ctx: None,\n        }\n    }\n\n    fn finish(mut self) -> VNode {\n        assert!(\n            self.spine.is_empty(),\n            \"expected all nested elements to be closed\"\n        );\n        if self.root_children.len() == 1 {\n            self.root_children.pop().unwrap()\n        } else {\n            self.root_children.into_iter().collect()\n        }\n    }\n\n    fn add_child(&mut self, child: VNode) {\n        if let Some(host) = self.spine.last_mut() {\n            host.add_child(child);\n        } else {\n            self.root_children.push(child);\n        }\n    }\n\n    fn pop_spine(&mut self) {\n        let top = self.spine.pop().expect(\"an element to close\");\n        self.add_child(top.into());\n    }\n\n    fn get_table_ctx(&mut self) -> &mut TableContext {\n        self.table_ctx.as_mut().expect(\"a table context\")\n    }\n\n    fn open_table_ctx(&mut self, alignment: Vec<Alignment>) {\n        assert!(self.table_ctx.is_none(), \"nested tables not supported\");\n        self.table_ctx = Some(TableContext {\n            next_cell_index: 0,\n            in_head: false,\n            has_body: false,\n            alignment,\n        });\n    }\n\n    fn close_table_ctx(&mut self) -> TableContext {\n        self.table_ctx.take().expect(\"expected to be in a table\")\n    }\n\n    fn start_tag(&mut self, tag: Tag) {\n        let wrapper = match tag {\n            Tag::Paragraph => VTag::new(\"p\"),\n            Tag::Heading { level, .. } => VTag::new(level.to_string()),\n            Tag::BlockQuote(_) => {\n                let mut el = VTag::new(\"blockquote\");\n                el.add_attribute(\"class\", \"blockquote\");\n                el\n            }\n            Tag::CodeBlock(code_block_kind) => {\n                self.spine.push(VTag::new(\"pre\"));\n\n                let mut el = VTag::new(\"code\");\n                if let CodeBlockKind::Fenced(lang) = code_block_kind {\n                    // Different color schemes may be used for different code blocks,\n                    // but a different library (likely js based at the moment) would be necessary to\n                    // actually provide the highlighting support by locating the\n                    // language classes and applying dom transforms on their contents.\n                    match lang.as_ref() {\n                        \"html\" => el.add_attribute(\"class\", \"html-language\"),\n                        \"rust\" => el.add_attribute(\"class\", \"rust-language\"),\n                        \"java\" => el.add_attribute(\"class\", \"java-language\"),\n                        \"c\" => el.add_attribute(\"class\", \"c-language\"),\n                        _ => {} // Add your own language highlighting support\n                    };\n                }\n\n                el\n            }\n            Tag::List(None) => VTag::new(\"ul\"),\n            Tag::List(Some(1)) => VTag::new(\"ol\"),\n            Tag::List(Some(ref start)) => {\n                let mut el = VTag::new(\"ol\");\n                el.add_attribute(\"start\", start.to_string());\n                el\n            }\n            Tag::Item => VTag::new(\"li\"),\n            Tag::Table(alignment) => {\n                self.open_table_ctx(alignment);\n                let mut el = VTag::new(\"table\");\n                el.add_attribute(\"class\", \"table\");\n                el\n            }\n            Tag::TableHead => {\n                let ctx = self.get_table_ctx();\n                ctx.next_cell_index = 0;\n                ctx.in_head = true;\n                self.spine.push(VTag::new(\"thead\"));\n                VTag::new(\"tr\")\n            }\n            Tag::TableRow => {\n                let ctx = self.get_table_ctx();\n                ctx.next_cell_index = 0;\n                if !ctx.has_body {\n                    ctx.has_body = true;\n                    self.spine.push(VTag::new(\"tbody\"));\n                }\n                VTag::new(\"tr\")\n            }\n            Tag::TableCell => {\n                let ctx = self.get_table_ctx();\n                let idx = ctx.next_cell_index;\n                ctx.next_cell_index += 1;\n\n                let mut tag = if ctx.in_head {\n                    let mut th = VTag::new(\"th\");\n                    th.add_attribute(\"scope\", \"col\");\n                    th\n                } else {\n                    VTag::new(\"td\")\n                };\n                match &ctx.alignment[idx] {\n                    Alignment::None => {}\n                    Alignment::Left => {\n                        tag.add_attribute(\"class\", \"text-left\");\n                    }\n                    Alignment::Center => {\n                        tag.add_attribute(\"class\", \"text-center\");\n                    }\n                    Alignment::Right => {\n                        tag.add_attribute(\"class\", \"text-right\");\n                    }\n                }\n                tag\n            }\n            Tag::Emphasis => {\n                let mut el = VTag::new(\"span\");\n                el.add_attribute(\"class\", \"font-italic\");\n                el\n            }\n            Tag::Strong => {\n                let mut el = VTag::new(\"span\");\n                el.add_attribute(\"class\", \"font-weight-bold\");\n                el\n            }\n            Tag::Link {\n                ref dest_url,\n                ref title,\n                link_type: _,\n                id: _,\n            } => {\n                let mut el = VTag::new(\"a\");\n                el.add_attribute(\"href\", dest_url.to_string());\n                let title = title.clone().into_string();\n                if !title.is_empty() {\n                    el.add_attribute(\"title\", title);\n                }\n                el\n            }\n            Tag::Image {\n                ref dest_url,\n                ref title,\n                link_type: _,\n                id: _,\n            } => {\n                let mut el = VTag::new(\"img\");\n                el.add_attribute(\"src\", dest_url.to_string());\n                let title = title.clone().into_string();\n                if !title.is_empty() {\n                    el.add_attribute(\"title\", title);\n                }\n                el\n            }\n            Tag::FootnoteDefinition(ref _footnote_id) => VTag::new(\"span\"), // Footnotes are not\n            // rendered as anything\n            // special\n            Tag::Strikethrough => {\n                let mut el = VTag::new(\"span\");\n                el.add_attribute(\"class\", \"text-decoration-strikethrough\");\n                el\n            }\n            Tag::HtmlBlock => VTag::new(\"div\"),\n            _ => {\n                gloo::console::log!(format!(\"Unhandled tag: {tag:#?}\"));\n                VTag::new(\"div\")\n            }\n        };\n        self.spine.push(wrapper);\n    }\n\n    fn end_tag(&mut self, tag: TagEnd) {\n        self.pop_spine();\n        match tag {\n            TagEnd::CodeBlock => {\n                self.pop_spine(); // Close <pre>\n            }\n            TagEnd::TableHead => {\n                self.pop_spine(); // Close <thead>\n                self.get_table_ctx().in_head = false;\n            }\n            TagEnd::Table => {\n                let ctx = self.close_table_ctx();\n                if ctx.has_body {\n                    self.pop_spine(); // Close <tbody>\n                }\n            }\n            _ => {}\n        }\n    }\n\n    fn write_event(&mut self, ev: Event) {\n        match ev {\n            Event::Start(tag) => self.start_tag(tag),\n            Event::End(tag) => self.end_tag(tag),\n            Event::Text(text) => self.add_child(VText::new(text.to_string()).into()),\n            Event::Rule => self.add_child(VTag::new(\"hr\").into()),\n            Event::SoftBreak => self.add_child(VText::new(\"\\n\").into()),\n            Event::HardBreak => self.add_child(VTag::new(\"br\").into()),\n            _ => gloo::console::log!(format!(\"Unhandled event: {ev:#?}\")),\n        };\n    }\n}\n\n/// Renders a string of Markdown to HTML with the default options (footnotes\n/// disabled, tables enabled).\npub fn render_markdown(src: &str) -> Html {\n    let mut writer = TagWriter::new();\n\n    let mut options = Options::empty();\n    options.insert(Options::ENABLE_TABLES);\n\n    for ev in Parser::new_ext(src, options) {\n        writer.write_event(ev);\n    }\n\n    writer.finish()\n}\n"
  },
  {
    "path": "examples/game_of_life/Cargo.toml",
    "content": "[package]\nname = \"game_of_life\"\nversion = \"0.1.4\"\nauthors = [\n    \"Diego Cardoso <dige0card0s0@hotmail.com>\",\n    \"Ilya Bogdanov <fumlead@gmail.com\",\n    \"Junjie Huang <huangjj.27@qq.com>\"\n]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\ngetrandom = { workspace = true }\nlog.workspace = true\nrand.workspace = true\nwasm-logger.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n"
  },
  {
    "path": "examples/game_of_life/README.md",
    "content": "# Game of Life Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fgame_of_life)](https://examples.yew.rs/game_of_life)\n\nThis example boasts a complete implementation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway's_Game_of_Life).\nYou can manually toggle cells by clicking on them or create a random layout by pressing the \"Random\" button.\n\n## Running\n\nThis example is quite resource intensive; it's recommended that you only use it with the `--release` flag:\n\n```bash\nRUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' trunk serve --release\n```\n\n## Concepts\n\n- Uses [`gloo_timer`](https://docs.rs/gloo-timers/latest/gloo_timers/) to automatically step the simulation.\n- Logs to the console using the [`weblog`](https://crates.io/crates/weblog) crate.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\nRUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' trunk serve --open\n```\n"
  },
  {
    "path": "examples/game_of_life/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/game_of_life/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Game of Life</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"css\" href=\"styles.css\" />\n    <link data-trunk rel=\"copy-file\" href=\"assets/favicon.ico\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/game_of_life/src/conway.rs",
    "content": "use rand::Rng;\n\npub struct Conway {\n    pub cellules: Vec<bool>,\n    pub width: usize,\n    pub height: usize,\n}\n\nimpl Conway {\n    pub fn new(width: usize, height: usize) -> Self {\n        Self {\n            cellules: vec![false; width * height],\n            width,\n            height,\n        }\n    }\n\n    pub fn alive(&self, row: usize, col: usize) -> bool {\n        self.cellules[row * self.width + col]\n    }\n\n    pub fn toggle(&mut self, row: usize, col: usize) {\n        let i = row * self.width + col;\n        self.cellules[i] = !self.cellules[i];\n    }\n\n    pub fn random_mutate(&mut self) {\n        let mut rng = rand::rng();\n        self.cellules.iter_mut().for_each(|c| *c = rng.random());\n    }\n\n    pub fn reset(&mut self) {\n        self.cellules.iter_mut().for_each(|c| *c = false);\n    }\n\n    pub fn step(&mut self) {\n        let mut to_toggle = Vec::new();\n        for row in 0..self.height {\n            for col in 0..self.width {\n                let n = self.live_neighbours(row as isize, col as isize);\n                if (self.alive(row, col) && (n <= 1 || n > 3)) || (!self.alive(row, col) && n == 3)\n                {\n                    to_toggle.push((row, col));\n                }\n            }\n        }\n        to_toggle\n            .iter()\n            .for_each(|(row, col)| self.toggle(*row, *col));\n    }\n\n    fn live_neighbours(&self, row: isize, col: isize) -> usize {\n        (-1..=1)\n            .flat_map(|r| (-1..=1).map(move |c| (r, c)))\n            .filter(|&(r, c)| (r, c) != (0, 0))\n            .filter(|&(r, c)| self.cellules[self.row_col_as_idx(row + r, col + c)])\n            .count()\n    }\n\n    fn row_col_as_idx(&self, row: isize, col: isize) -> usize {\n        let row = wrap(row, self.height as isize);\n        let col = wrap(col, self.width as isize);\n        row * self.width + col\n    }\n}\n\nfn wrap(idx: isize, range: isize) -> usize {\n    ((idx % range + range) % range) as usize // because % has sign of dividend\n}\n"
  },
  {
    "path": "examples/game_of_life/src/main.rs",
    "content": "use gloo::timers::callback::Interval;\nuse yew::html::Scope;\nuse yew::{classes, html, Component, Context, Html};\n\nmod conway;\n\npub enum Msg {\n    Random,\n    Start,\n    Step,\n    Reset,\n    Stop,\n    ToggleCellule((usize, usize)),\n    Tick,\n}\n\npub struct App {\n    active: bool,\n    conway: conway::Conway,\n    _interval: Interval,\n}\n\nimpl App {\n    fn view_cellule(&self, row: usize, col: usize, link: &Scope<Self>) -> Html {\n        let status = if self.conway.alive(row, col) {\n            \"cellule-live\"\n        } else {\n            \"cellule-dead\"\n        };\n        html! {\n            <div class={classes!(\"game-cellule\", status)}\n                onclick={link.callback(move |_| Msg::ToggleCellule((row,col)))}>\n            </div>\n        }\n    }\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let callback = ctx.link().callback(|_| Msg::Tick);\n\n        Self {\n            active: false,\n            conway: conway::Conway::new(53, 40),\n            _interval: Interval::new(200, move || callback.emit(())),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        let mut render = true;\n        match msg {\n            Msg::Random => {\n                self.conway.random_mutate();\n                log::info!(\"Random\");\n            }\n            Msg::Start => {\n                self.active = true;\n                log::info!(\"Start\");\n                render = false;\n            }\n            Msg::Step => {\n                self.conway.step();\n            }\n            Msg::Reset => {\n                self.conway.reset();\n                log::info!(\"Reset\");\n            }\n            Msg::Stop => {\n                self.active = false;\n                log::info!(\"Stop\");\n                render = false;\n            }\n            Msg::ToggleCellule((row, col)) => self.conway.toggle(row, col),\n            Msg::Tick => {\n                if self.active {\n                    self.conway.step();\n                } else {\n                    render = false;\n                }\n            }\n        }\n        render\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let cell_rows = self\n            .conway\n            .cellules\n            .chunks(self.conway.width)\n            .enumerate()\n            .map(|(row, cellules)| {\n                let cells = cellules\n                    .iter()\n                    .enumerate()\n                    .map(|(col, _)| self.view_cellule(row, col, ctx.link()));\n                html! {\n                    <div class=\"game-row\">\n                        { for cells }\n                    </div>\n                }\n            });\n\n        html! {\n            <div>\n                <section class=\"game-container\">\n                    <header class=\"app-header\">\n                        <img alt=\"The app logo\" src=\"favicon.ico\" class=\"app-logo\"/>\n                        <h1 class=\"app-title\">{ \"Game of Life\" }</h1>\n                    </header>\n                    <section class=\"game-area\">\n                        <div class=\"game-of-life\">\n                            { for cell_rows }\n                        </div>\n                        <div class=\"game-buttons\">\n                            <button class=\"game-button\" onclick={ctx.link().callback(|_| Msg::Random)}>{ \"Random\" }</button>\n                            <button class=\"game-button\" onclick={ctx.link().callback(|_| Msg::Step)}>{ \"Step\" }</button>\n                            <button class=\"game-button\" onclick={ctx.link().callback(|_| Msg::Start)}>{ \"Start\" }</button>\n                            <button class=\"game-button\" onclick={ctx.link().callback(|_| Msg::Stop)}>{ \"Stop\" }</button>\n                            <button class=\"game-button\" onclick={ctx.link().callback(|_| Msg::Reset)}>{ \"Reset\" }</button>\n                        </div>\n                    </section>\n                </section>\n                <footer class=\"app-footer\">\n                    <strong class=\"footer-text\">\n                      { \"Game of Life - a yew experiment \" }\n                    </strong>\n                    <a href=\"https://github.com/yewstack/yew\" target=\"_blank\">{ \"source\" }</a>\n                </footer>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n    log::trace!(\"Initializing yew...\");\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/game_of_life/styles.css",
    "content": "html,\nbody {\n  margin: 0;\n  padding: 0;\n  text-align: center;\n}\n\nbody {\n  font: 14px \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  line-height: 1.4em;\n  color: #4d4d4d;\n  min-width: 230px;\n  max-width: 1000px;\n  margin: 0 auto;\n  -webkit-font-smoothing: antialiased;\n  -moz-font-smoothing: antialiased;\n  font-smoothing: antialiased;\n  font-weight: 300;\n  background-color: #000000;\n}\n\n.app-logo {\n  animation: app-logo-scale infinite 4s linear;\n  height: 80px;\n  width: 80px;\n}\n\n.app-header {\n  background-color: #000;\n  height: 130px;\n  color: aliceblue;\n}\n\n.app-title {\n  font-size: 24px;\n  width: 100%;\n  font-weight: 100;\n  text-align: center;\n  -webkit-text-rendering: optimizeLegibility;\n  -moz-text-rendering: optimizeLegibility;\n  text-rendering: optimizeLegibility;\n}\n\n.app-footer {\n  background-color: #000000;\n  height: 30px;\n  padding: 10px;\n}\n\n.footer-text {\n  color: aliceblue;\n  padding-left: 20px;\n  font-size: 14px;\n}\n\n.game-area {\n  width: 94%;\n  margin: 20px auto;\n}\n\n.game-container {\n  background: #000000;\n  margin: 20px 0 0px 0;\n}\n\n.game-of-life {\n  display: inline-block;\n  background-color: aliceblue;\n  width: max-content;\n  overflow: hidden;\n}\n\n.game-row {\n  line-height: 0;\n}\n\n.game-cellule {\n  display: inline-block;\n  width: 8px;\n  height: 8px;\n  border: 1px solid #ccc;\n}\n\n.cellule-dead {\n  background-color: white;\n}\n\n.cellule-live {\n  background-color: black;\n}\n\n.game-buttons {\n  width: 100%;\n  margin-top: 20px;\n}\n\n@keyframes app-logo-scale {\n  from {\n    transform: scale(0.8);\n  }\n  to {\n    transform: scale(1.2);\n  }\n}\n"
  },
  {
    "path": "examples/immutable/Cargo.toml",
    "content": "[package]\nname = \"immutable\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nimplicit-clone = { workspace = true, features = [\"map\"] }\nwasm-bindgen.workspace = true\nweb-sys.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/immutable/README.md",
    "content": "# Immutable Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fimmutable)](https://examples.yew.rs/immutable)\n\nThis is a technical demonstration for how to use immutables types in Yew.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/immutable/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/immutable/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Yew • Immutable</title>\n  <link data-trunk rel=\"scss\" href=\"index.scss\"/>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@900&display=swap\" rel=\"stylesheet\">\n</head>\n\n<body></body>\n\n</html>\n"
  },
  {
    "path": "examples/immutable/index.scss",
    "content": "$font-stack:    Roboto, sans-serif;\n$primary-color: #f5f5f5;\n\nbody {\n    font: 100% $font-stack;\n    color: black;\n    background-color: $primary-color;\n    margin: 0 auto;\n    min-width: 230px;\n    max-width: 550px;\n}\n"
  },
  {
    "path": "examples/immutable/src/array.rs",
    "content": "use implicit_clone::unsync::*;\nuse wasm_bindgen::{JsCast, UnwrapThrowExt};\nuse web_sys::{HtmlInputElement, KeyboardEvent};\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct FolksViewProps {\n    folks: IArray<IString>,\n}\n\n#[function_component(FolksView)]\nfn folks_view(props: &FolksViewProps) -> Html {\n    html! {\n        <>\n        <p>{\"Hello to:\"}</p>\n        <ul>\n        { for props.folks.iter().map(|s| html!(<li>{s}</li>)) }\n        </ul>\n        </>\n    }\n}\n\n#[function_component(ArrayExample)]\npub fn array_example() -> Html {\n    let folks = use_state(IArray::<IString>::default);\n    let onkeyup = {\n        let folks = folks.clone();\n        Callback::from(move |e: KeyboardEvent| {\n            if e.key() == \"Enter\" {\n                let event: Event = e.dyn_into().unwrap_throw();\n                let event_target = event.target().unwrap_throw();\n                let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();\n                let name = target.value();\n                target.set_value(\"\");\n\n                folks.set(\n                    folks\n                        .iter()\n                        .cloned()\n                        .chain(std::iter::once(IString::from(name)))\n                        .collect(),\n                );\n            }\n        })\n    };\n\n    html! {\n        <>\n        <h2>{\"Input\"}</h2>\n        <input {onkeyup} />\n        <h2>{\"Output\"}</h2>\n        <FolksView folks={&*folks} />\n        </>\n    }\n}\n"
  },
  {
    "path": "examples/immutable/src/main.rs",
    "content": "mod array;\nmod map;\nmod string;\n\nuse yew::prelude::*;\n\nuse self::array::*;\nuse self::map::*;\nuse self::string::*;\n\n#[function_component]\nfn App() -> Html {\n    html! {\n        <>\n            <h1>{ \"IString Example\" }</h1>\n            <StringExample />\n            <hr/>\n            <h1>{ \"IArray Example\" }</h1>\n            <ArrayExample />\n            <hr/>\n            <h1>{ \"IMap Example\" }</h1>\n            <MapExample />\n        </>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/immutable/src/map.rs",
    "content": "use implicit_clone::unsync::*;\nuse wasm_bindgen::{JsCast, UnwrapThrowExt};\nuse web_sys::{HtmlInputElement, KeyboardEvent};\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct DisplayProps {\n    values: IMap<u32, IString>,\n}\n\n#[function_component]\nfn Display(props: &DisplayProps) -> Html {\n    html! {\n        <>\n        <p>{\"Hello to:\"}</p>\n        <ul>\n        { for props.values.iter().map(|(i, s)| html!(<li>{i}{\" => \"}{s}</li>)) }\n        </ul>\n        </>\n    }\n}\n\npub struct MapExample {\n    values: IMap<u32, IString>,\n}\n\npub enum MapExampleMessage {\n    AddName(String),\n    Noop,\n}\n\nimpl Component for MapExample {\n    type Message = MapExampleMessage;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            values: Default::default(),\n        }\n    }\n\n    fn update(&mut self, _: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            MapExampleMessage::AddName(name) => {\n                self.values = self\n                    .values\n                    .iter()\n                    .map(|(&k, v)| (k, v.clone()))\n                    .chain(std::iter::once((\n                        self.values.len() as u32,\n                        IString::from(name),\n                    )))\n                    .collect();\n                true\n            }\n            MapExampleMessage::Noop => false,\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let link = ctx.link();\n        let onkeyup = link.callback(|e: KeyboardEvent| {\n            if e.key() == \"Enter\" {\n                let event: Event = e.dyn_into().unwrap_throw();\n                let event_target = event.target().unwrap_throw();\n                let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();\n                let value = target.value();\n                target.set_value(\"\");\n                MapExampleMessage::AddName(value)\n            } else {\n                MapExampleMessage::Noop\n            }\n        });\n\n        html! {\n            <>\n            <h2>{\"Input\"}</h2>\n            <input {onkeyup} />\n            <h2>{\"Output\"}</h2>\n            <Display values={&self.values} />\n            </>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/immutable/src/string.rs",
    "content": "use implicit_clone::unsync::*;\nuse wasm_bindgen::{JsCast, UnwrapThrowExt};\nuse web_sys::{HtmlInputElement, InputEvent};\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct DisplayProps {\n    name: IString,\n}\n\n#[function_component]\nfn Display(props: &DisplayProps) -> Html {\n    html! {\n        <p>{\"Hello \"}{&props.name}{\"!\"}</p>\n    }\n}\n\npub struct StringExample {\n    name: IString,\n}\n\npub enum StringExampleMessage {\n    UpdateName(String),\n}\n\nimpl Component for StringExample {\n    type Message = StringExampleMessage;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            name: \"World\".into(),\n        }\n    }\n\n    fn update(&mut self, _: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            StringExampleMessage::UpdateName(name) => {\n                self.name = name.into();\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let link = ctx.link();\n        let oninput = link.callback(|e: InputEvent| {\n            let event: Event = e.dyn_into().unwrap_throw();\n            let event_target = event.target().unwrap_throw();\n            let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();\n            StringExampleMessage::UpdateName(target.value())\n        });\n\n        html! {\n            <>\n            <h2>{\"Input\"}</h2>\n            <input value={&self.name} {oninput} />\n            <h2>{\"Output\"}</h2>\n            <Display name={&self.name} />\n            </>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/inner_html/Cargo.toml",
    "content": "[package]\nname = \"inner_html\"\nversion = \"0.1.0\"\nauthors = [\"Garrett Berg <vitiral@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\"console\", \"Document\", \"Element\", \"Node\", \"Window\"]\n"
  },
  {
    "path": "examples/inner_html/README.md",
    "content": "# Inner HTML Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Finner_html)](https://examples.yew.rs/inner_html)\n\nThis example renders unescaped HTML by manually handling the DOM element.\n\n## Concepts\n\n- Manually creating `Html` without the `html!` macro.\n- Using `web-sys` to manipulate the DOM.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/inner_html/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/inner_html/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Inner HTML</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/inner_html/src/document.html",
    "content": "<h2>Inline HTML with SVG</h2>\n<p>\n  The whole contents of this page is stored as a constant HTML string in the\n  Rust source code. The code queries the DOM, creates a new element, and applies\n  this snippet of HTML to the element's innerHTML.\n</p>\n<svg height=\"250\" width=\"500\">\n  <polygon\n    points=\"220,10 300,210 170,250 123,234\"\n    style=\"fill: lime; stroke: purple; stroke-width: 1\"\n  />\n  Sorry, your browser does not support inline SVG.\n</svg>\n"
  },
  {
    "path": "examples/inner_html/src/main.rs",
    "content": "use yew::{Component, Context, Html};\n\nconst HTML: &str = include_str!(\"document.html\");\n\npub struct App;\n\nimpl Component for App {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        Html::from_html_unchecked(HTML.into())\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/js_callback/.gitignore",
    "content": "# this dir needs its own .gitignore because it has more build artificats\ntrunk_post_build\n"
  },
  {
    "path": "examples/js_callback/Cargo.toml",
    "content": "[package]\nname = \"js_callback\"\nversion = \"0.1.0\"\nauthors = [\"Scott Steele <scottlsteele@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nwasm-bindgen.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nwasm-bindgen-futures.workspace = true\njs-sys.workspace = true\n"
  },
  {
    "path": "examples/js_callback/README.md",
    "content": "# Js Callback Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fjs_callback)](https://examples.yew.rs/js_callback)\n\n## Concepts\n\nThe example uses wasm-bindgen to import functionality from Javascript.\nTo learn more about the subject, refer to [\"The `wasm-binden` Guide\"](https://wasm-bindgen.github.io/wasm-bindgen/examples/import-js.html).\n\nThis example also demonstrates how to delay the loading of the snippet using Suspense.\n\n### Serving JS files \n\nJS files can be served when they're present in `dist` directory. There are two ways to copy these files:\n1. Use [JS Snippets](https://wasm-bindgen.github.io/wasm-bindgen/reference/js-snippets.html). \n2. Use trunk to copy the file and import it manually\n\n### Using JS Snippets\n\nThis example uses this approach. `wasm-bindgen` handles copying the files with this approach. \nAll you have to do is define the `extern` block. The files are copied to `dist/snippets/<bin-name>-<hash>/` directory.\n\nIf the file is to be loaded with the initial load, you can simply use the JS imports, as shown we `imp.js`.\n\nIf you would like to lazy-load the JS module, you need to use the `trunk`'s `post_build` hook \nfrom [`trunk_post_build.rs`](trunk_post_build.rs) access the snippets' directory path at runtime and use in \n[`import()` for dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports)\n\n\n### Copying file with trunk\n\nThis approach is only needed if the JS module is to be lazy-loaded. It allows us to skip the step where we \nprovide the snippets' directory path to the app. Instead, the file is copied at a known location that can \neasily be referenced im `import()` statement.\n\n## Improvements\n\nThis example is a purely technical demonstration and lacks an actual purpose.\nThe best way to improve this example would be to incorporate this concept into a small application.\n\n- Do something more complex in the Javascript code to demonstrate more of `wasm-bindgen`'s capabilities.\n- Improve the presentation of the example with CSS.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/js_callback/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n\n[[hooks]]\nstage = \"pre_build\"\ncommand = \"rustc\"\ncommand_arguments = [\"trunk_post_build.rs\"]\n\n[[hooks]]\nstage = \"post_build\"\ncommand = \"./trunk_post_build\"\n\n"
  },
  {
    "path": "examples/js_callback/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Js Callback</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/js_callback/js/imp.js",
    "content": "export function hello() {\n    return \"very important message\"\n}\n"
  },
  {
    "path": "examples/js_callback/js/unimp.js",
    "content": "export function bye() {\n    return \"unimportant message\"\n}\n"
  },
  {
    "path": "examples/js_callback/src/bindings.rs",
    "content": "use wasm_bindgen::prelude::*;\n\n// https://github.com/rustwasm/wasm-bindgen/issues/3208\n#[wasm_bindgen(inline_js = \"export function import2(path) { return import(path); }\")]\nextern \"C\" {\n    // this should be in js-sys but is not. see https://github.com/rustwasm/wasm-bindgen/issues/2865\n    // pub fn import(s: &str) -> js_sys::Promise;\n    #[wasm_bindgen(js_name = \"import2\")]\n    pub fn import(name: &str) -> js_sys::Promise;\n\n    pub type Window;\n\n    #[wasm_bindgen(method, getter, js_name = \"wasmBindgenSnippetsPath\")]\n    pub fn wasm_bindgen_snippets_path(this: &Window) -> String;\n}\n\n#[wasm_bindgen(module = \"/js/imp.js\")]\nextern \"C\" {\n    #[wasm_bindgen]\n    pub fn hello() -> String;\n}\n\n#[wasm_bindgen]\nextern \"C\" {\n    pub type UnimpModule;\n\n    #[wasm_bindgen(method)]\n    pub fn bye(this: &UnimpModule) -> String;\n}\n\n#[wasm_bindgen(module = \"/js/unimp.js\")]\nextern \"C\" {\n    /// This exists so that wasm bindgen copies js/unimp.js to\n    /// dist/snippets/<bin-name>-<hash>/js/uninp.js\n    #[wasm_bindgen]\n    fn _dummy_fn_so_wasm_bindgen_copies_over_the_file();\n}\n"
  },
  {
    "path": "examples/js_callback/src/main.rs",
    "content": "use std::sync::OnceLock;\n\nuse wasm_bindgen::prelude::*;\nuse wasm_bindgen::JsCast;\nuse wasm_bindgen_futures::JsFuture;\nuse yew::prelude::*;\nuse yew::suspense::{use_future, SuspensionResult};\n\nmod bindings;\n\nstatic WASM_BINDGEN_SNIPPETS_PATH: OnceLock<String> = OnceLock::new();\n\n#[function_component]\nfn Important() -> Html {\n    let msg = use_memo((), |_| bindings::hello());\n    html! {\n        <>\n            <h2>{\"Important\"}</h2>\n            <p>{msg}</p>\n        </>\n    }\n}\n\n#[hook]\nfn use_do_bye() -> SuspensionResult<String> {\n    let path = WASM_BINDGEN_SNIPPETS_PATH\n        .get()\n        .map(|path| format!(\"{path}/js/unimp.js\"))\n        .unwrap();\n    let s = use_future(|| async move {\n        let promise = bindings::import(&path);\n        let module = JsFuture::from(promise).await.unwrap_throw();\n        let module = module.unchecked_into::<bindings::UnimpModule>();\n        module.bye()\n    })?;\n    Ok((*s).clone())\n}\n\n#[function_component]\nfn UnImportant() -> HtmlResult {\n    let msg = use_do_bye()?;\n    Ok(html! {\n        <>\n            <h2>{\"Unimportant\"}</h2>\n            <p>{msg}</p>\n        </>\n    })\n}\n\n#[function_component]\nfn App() -> Html {\n    let showing_unimportant = use_state(|| false);\n\n    let show_unimportant = {\n        let showing_unimportant = showing_unimportant.clone();\n        move |_| showing_unimportant.set(true)\n    };\n    let fallback = html! {\"fallback\"};\n    html! {\n        <main>\n            <Important />\n            <button onclick={show_unimportant}>{\"load unimportant data\"}</button>\n            <Suspense {fallback}>\n                if *showing_unimportant {\n                    <UnImportant />\n                }\n            </Suspense>\n        </main>\n    }\n}\n\nfn main() {\n    let wasm_bindgen_snippets_path = js_sys::global()\n        .unchecked_into::<bindings::Window>()\n        .wasm_bindgen_snippets_path();\n    WASM_BINDGEN_SNIPPETS_PATH\n        .set(wasm_bindgen_snippets_path)\n        .expect(\"unreachable\");\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/js_callback/trunk_post_build.rs",
    "content": "use std::fs;\nuse std::io::{Read, Write};\n\nfn read_env(env: &'static str) -> String {\n    std::env::var(env).unwrap_or_else(|e| panic!(\"can't read {} env var: {}\", env, e))\n}\n\nfn main() {\n    let stage_dir = read_env(\"TRUNK_STAGING_DIR\");\n    let mut res = fs::read_dir(format!(\"{stage_dir}/snippets\")).expect(\"no snippets dir in stage\");\n    let dir = res\n        .next()\n        .expect(\"there must be one snippets dir present\")\n        .expect(\"can't read snippets dir\");\n    let dir_name = dir.file_name().to_string_lossy().to_string();\n    let mut index_html =\n        fs::File::open(format!(\"{stage_dir}/index.html\")).expect(\"can't open index.html\");\n    let mut html = String::new();\n    index_html\n        .read_to_string(&mut html)\n        .expect(\"can't read index.html\");\n\n    let mut split = html\n        .split(\"</head>\")\n        .map(|it| it.to_string())\n        .collect::<Vec<String>>();\n\n    let public_url = read_env(\"TRUNK_PUBLIC_URL\");\n    let public_url = public_url.strip_suffix(\"/\").unwrap_or(&public_url);\n    let wasm_bindgen_snippets_path = format!(\"{public_url}/snippets/{dir_name}\");\n\n    split.insert(1,  format!(\"<script>window.wasmBindgenSnippetsPath = '{wasm_bindgen_snippets_path}';</script></head>\"));\n    let joined = split.join(\"\");\n    drop(index_html);\n    let mut index_html = fs::File::options()\n        .write(true)\n        .truncate(true)\n        .open(format!(\"{stage_dir}/index.html\"))\n        .expect(\"can't open index.html\");\n    index_html\n        .write_all(joined.as_ref())\n        .expect(\"can't write index.html\")\n}\n"
  },
  {
    "path": "examples/keyed_list/Cargo.toml",
    "content": "[package]\nname = \"keyed_list\"\nversion = \"0.1.0\"\nauthors = [\"Thomas Lacroix <toto.rigolo@free.fr>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nfake = \"4.0.0\"\ngetrandom = { workspace = true }\ninstant = { workspace = true }\nlog.workspace = true\nrand.workspace = true\nwasm-logger.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"HtmlElement\",\n    \"HtmlInputElement\",\n]\n"
  },
  {
    "path": "examples/keyed_list/README.md",
    "content": "# Keyed List Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fkeyed_list)](https://examples.yew.rs/keyed_list)\n\nThis example consists of a list which can be manipulated in various ways.\n\n### Notes\n\nIf you would like to view this example as a performance demonstration, run this example in `release` mode.\n\n## Concepts\n\nDemonstrates how using keyed elements improves the performance of comparing changes to lists.\n\n## Improvements\n\n- Improve the name and address generation so that they don't look like gibberish\n- Show the time it took to update the DOM on the page instead of just the console\n- Improve the presentation of the example with CSS\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\nRUSTFLAGS='--cfg getrandom_backend=\"wasm_js\"' trunk serve --open\n```\n"
  },
  {
    "path": "examples/keyed_list/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/keyed_list/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Keyed list</title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css\" integrity=\"sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm\" crossorigin=\"anonymous\">\n    <link data-trunk rel=\"css\" href=\"styles.css\" />\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/keyed_list/src/main.rs",
    "content": "use std::cell::RefCell;\n\nuse instant::Instant;\nuse person::PersonType;\nuse web_sys::{HtmlElement, HtmlInputElement};\nuse yew::html::Scope;\nuse yew::prelude::*;\n\nmod person;\nmod random;\n\npub enum Msg {\n    CreatePersons(usize),\n    CreatePersonsPrepend(usize),\n    ChangeRatio(f64),\n    DeletePersonById(usize),\n    DeleteEverybody,\n    SwapRandom,\n    ReverseList,\n    SortById,\n    SortByName,\n    SortByAge,\n    SortByAddress,\n    ToggleKeyed,\n}\n\npub struct App {\n    persons: Vec<PersonType>,\n    last_id: usize,\n    keyed: bool,\n    build_component_ratio: f64,\n    delta_ref: NodeRef,\n    last_view: RefCell<Option<Instant>>,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            persons: Vec::with_capacity(200),\n            last_id: 0,\n            keyed: true,\n            build_component_ratio: 0.5,\n            delta_ref: NodeRef::default(),\n            last_view: RefCell::default(),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::CreatePersons(n) => {\n                for _ in 0..n {\n                    self.last_id += 1;\n                    self.persons.push(PersonType::new_random(\n                        self.last_id,\n                        self.build_component_ratio,\n                    ));\n                }\n                true\n            }\n            Msg::CreatePersonsPrepend(n) => {\n                for _ in 0..n {\n                    self.last_id += 1;\n                    self.persons.insert(\n                        0,\n                        PersonType::new_random(self.last_id, self.build_component_ratio),\n                    );\n                }\n                true\n            }\n            Msg::ChangeRatio(ratio) => {\n                #[allow(clippy::float_cmp)] // it's fine here?\n                if self.build_component_ratio != ratio {\n                    self.build_component_ratio = ratio;\n                    log::info!(\"Ratio changed: {}\", ratio);\n                    true\n                } else {\n                    false\n                }\n            }\n            Msg::DeletePersonById(id) => {\n                if let Some(idx) = self.persons.iter().position(|p| p.info().id == id) {\n                    self.persons.remove(idx);\n                    true\n                } else {\n                    false\n                }\n            }\n            Msg::DeleteEverybody => {\n                self.persons.clear();\n                true\n            }\n            Msg::SwapRandom => {\n                if let Some((a, b)) = random::choose_two_distinct_mut(&mut self.persons) {\n                    log::info!(\"Swapping {} and {}.\", a.info().id, b.info().id);\n                    std::mem::swap(a, b);\n                    true\n                } else {\n                    false\n                }\n            }\n            Msg::ReverseList => {\n                self.persons.reverse();\n                true\n            }\n            Msg::SortById => {\n                self.persons.sort_unstable_by_key(|a| a.info().id);\n                true\n            }\n            Msg::SortByName => {\n                self.persons\n                    .sort_unstable_by(|a, b| a.info().name.cmp(&b.info().name));\n                true\n            }\n            Msg::SortByAge => {\n                self.persons.sort_by_key(|p| p.info().age);\n                true\n            }\n            Msg::SortByAddress => {\n                self.persons\n                    .sort_unstable_by(|a, b| a.info().address.cmp(&b.info().address));\n                true\n            }\n            Msg::ToggleKeyed => {\n                self.keyed = !self.keyed;\n                true\n            }\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        let time_after = Instant::now();\n        let elapsed_max = time_after - self.last_view.get_mut().take().unwrap();\n        log::info!(\"Rendering started {} ms ago.\", elapsed_max.as_millis());\n        let output = self.delta_ref.cast::<HtmlElement>().unwrap();\n        let delta_text = format!(\"The last rendering took {} ms\", elapsed_max.as_millis());\n        output.set_inner_text(&delta_text);\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let mut last_view = self.last_view.borrow_mut();\n        if last_view.is_none() {\n            *last_view = Some(Instant::now());\n        }\n\n        html! {\n            <div class=\"container\">\n                <div class=\"row\">\n                    <p class=\"h2\" ref={self.delta_ref.clone()}/>\n                    <hr />\n                </div>\n                { self.action_view(ctx.link()) }\n                { self.info_view() }\n            </div>\n        }\n    }\n}\n\nimpl App {\n    fn action_view(&self, link: &Scope<Self>) -> Html {\n        html! {\n            <>\n                { self.button_view(link) }\n                <div class=\"row\">\n                    <div class=\"col\">\n                        <p class=\"h5\">\n                            { \"Person type ratio (0=only tags <= ratio <= 1=only components): \" }\n                            { self.build_component_ratio }\n                        </p>\n                        <input name=\"ratio\" type=\"range\" class=\"form-control-range\" min=\"0.0\" max=\"1.0\" step=\"any\"\n                            oninput={link.callback(|e: InputEvent| {\n                                let input: HtmlInputElement = e.target_unchecked_into();\n                                Msg::ChangeRatio(input.value_as_number())\n                            })}\n                        />\n                    </div>\n                </div>\n            </>\n        }\n    }\n\n    fn button_view(&self, link: &Scope<Self>) -> Html {\n        html! {\n            <>\n                <div class=\"row\">\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-danger\" onclick={link.callback(|_| Msg::DeleteEverybody)}>\n                            { \"Delete everybody\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-success\" onclick={link.callback(|_| Msg::CreatePersons(1))}>\n                            { \"Create 1\" }\n                    </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-success\" onclick={link.callback(|_| Msg::CreatePersons(5))}>\n                            { \"Create 5\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-success\" onclick={link.callback(|_| Msg::CreatePersons(100))}>\n                            { \"Create 100\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-success\" onclick={link.callback(|_| Msg::CreatePersons(500))}>\n                            { \"Create 500\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-success\" onclick={link.callback(|_| Msg::CreatePersonsPrepend(1))}>\n                            { \"Prepend 1\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-success\" onclick={link.callback(|_| Msg::CreatePersonsPrepend(5))}>\n                            { \"Prepend 5\" }\n                        </button>\n                    </div>\n                </div>\n                <div class=\"row\">\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-warning\" onclick={link.callback(|_| Msg::ToggleKeyed)}>\n                            { if self.keyed { \"Disable keys\" } else { \"Enable keys\" } }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-info\" onclick={link.callback(|_| Msg::SwapRandom)}>\n                            { \"Swap random\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-info\" onclick={link.callback(|_| Msg::ReverseList)}>\n                            { \"Reverse list\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-info\" onclick={link.callback(|_| Msg::SortById)}>\n                            { \"Sort by id\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-info\" onclick={link.callback(|_| Msg::SortByName)}>\n                            { \"Sort by name\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-info\" onclick={link.callback(|_| Msg::SortByAge)}>\n                            { \"Sort by age\" }\n                        </button>\n                    </div>\n                    <div class=\"col\">\n                        <button class=\"btn_size alert alert-info\" onclick={link.callback(|_| Msg::SortByAddress)}>\n                            { \"Sort by address\" }\n                        </button>\n                    </div>\n                </div>\n            </>\n        }\n    }\n\n    fn info_view(&self) -> Html {\n        let ids = if self.persons.len() < 20 {\n            self.persons\n                .iter()\n                .map(|p| p.info().id.to_string())\n                .collect::<Vec<_>>()\n                .join(\" \")\n        } else {\n            String::from(\"<too many>\")\n        };\n        html! {\n            <div>\n                <p class=\"h5\">{ \"Number of persons: \" }{ self.persons.len() }</p>\n                <p class=\"h5\">{ \"Ids: \" }{ ids }</p>\n                <hr />\n                <div class=\"persons\">\n                    { for self.persons.iter().map(|p| p.render(self.keyed)) }\n                </div>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/keyed_list/src/person.rs",
    "content": "use std::rc::Rc;\n\nuse fake::faker::address::raw::*;\nuse fake::faker::name::raw::*;\nuse fake::locales::*;\nuse fake::Fake;\nuse yew::{html, Component, Context, Html, Properties};\n\nuse crate::random;\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct PersonInfo {\n    pub id: usize,\n    pub name: Rc<str>,\n    pub address: Rc<str>,\n    pub age: usize,\n}\nimpl PersonInfo {\n    pub fn new_random(id: usize) -> Self {\n        let address = {\n            let no = random::range_exclusive(1, 300);\n            let state = StateAbbr(EN).fake::<String>();\n            let city = CityName(EN).fake::<String>();\n            let street = StreetName(EN).fake::<String>();\n\n            Rc::from(format!(\"{no} {street} St., {city}, {state}\").as_str())\n        };\n\n        Self {\n            id,\n            name: Rc::from(Name(EN).fake::<String>().as_str()),\n            age: random::range_exclusive(7, 77),\n            address,\n        }\n    }\n\n    fn render(&self) -> Html {\n        html! {\n            <div class=\"card w-50 card_style\">\n                <div class=\"card-body\">\n                    <h5 class=\"card-title\">{ format!(\"{} - {}\", &self.id, &self.name) }</h5>\n                    <p class=\"card-text\">{ format!(\"Age: {}\", &self.age) }</p>\n                    <p class=\"card-text\">{ format!(\"Address: {}\", &self.address) }</p>\n                </div>\n            </div>\n        }\n    }\n}\n\n#[derive(Debug, Eq, PartialEq, Properties)]\npub struct PersonProps {\n    info: PersonInfo,\n}\n\npub struct PersonComponent;\n\nimpl Component for PersonComponent {\n    type Message = ();\n    type Properties = PersonProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"text-info\" id={ctx.props().info.id.to_string()}>\n                { ctx.props().info.render() }\n            </div>\n        }\n    }\n}\n\npub enum PersonType {\n    Inline(PersonInfo),\n    Component(PersonInfo),\n}\nimpl PersonType {\n    pub fn info(&self) -> &PersonInfo {\n        match self {\n            Self::Inline(info) => info,\n            Self::Component(info) => info,\n        }\n    }\n\n    pub fn new_random(id: usize, ratio: f64) -> Self {\n        let info = PersonInfo::new_random(id);\n        if random::chance(ratio) {\n            Self::Inline(info)\n        } else {\n            Self::Component(info)\n        }\n    }\n\n    pub fn render(&self, keyed: bool) -> Html {\n        match self {\n            Self::Inline(info) => {\n                if keyed {\n                    html! {\n                        <div key={info.id.to_string()} class=\"text-danger\" id={info.id.to_string()}>\n                            { info.render() }\n                        </div>\n                    }\n                } else {\n                    html! {\n                        <div class=\"text-danger\" id={info.id.to_string()}>\n                            { info.render() }\n                        </div>\n                    }\n                }\n            }\n            Self::Component(info) => {\n                if keyed {\n                    html! { <PersonComponent key={info.id.to_string()} info={info.clone()} /> }\n                } else {\n                    html! { <PersonComponent info={info.clone()} /> }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/keyed_list/src/random.rs",
    "content": "use rand::distr::Bernoulli;\nuse rand::Rng;\n\n/// `0 <= p <= 1`\npub fn chance(p: f64) -> bool {\n    let d = Bernoulli::new(p).unwrap();\n    rand::rng().sample(d)\n}\n\n/// half-open: [min, max)\npub fn range_exclusive(min: usize, max: usize) -> usize {\n    rand::rng().random_range(min..max)\n}\n\npub fn choose_two_distinct_mut<T>(items: &mut [T]) -> Option<(&mut T, &mut T)> {\n    let (lo, hi) = {\n        // Choose two distinct indices `(a, b)` such that `a < b`.\n        match items.len() {\n            0 | 1 => return None,\n            _ => {\n                let indexes = rand::seq::index::sample(&mut rand::rng(), items.len(), 2);\n                let (a, b) = (indexes.index(0), indexes.index(1));\n                if a < b {\n                    (a, b)\n                } else {\n                    (b, a)\n                }\n            }\n        }\n    };\n\n    // a = `items[0..hi]` which contains `lo` because `lo < hi`\n    // b = `items[hi..]` where `items[hi] == b[0]`\n    let (a, b) = items.split_at_mut(hi);\n    Some((&mut a[lo], &mut b[0]))\n}\n"
  },
  {
    "path": "examples/keyed_list/styles.css",
    "content": ".component-person {\n  color: blue;\n}\n\n.basic-person {\n  color: red;\n}\n\n.btn_size {\n  width: 100%;\n  height: 75px;\n}\n\n.card_style {\n  margin:5px;\n}\n"
  },
  {
    "path": "examples/mount_point/Cargo.toml",
    "content": "[package]\nname = \"mount_point\"\nversion = \"0.1.0\"\nauthors = [\"Ben Berman <ben@standardbots.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nwasm-bindgen.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n  \"CanvasRenderingContext2d\",\n  \"Document\",\n  \"DomTokenList\",\n  \"Element\",\n  \"HtmlCanvasElement\",\n  \"Node\",\n  \"Window\"\n]\n"
  },
  {
    "path": "examples/mount_point/README.md",
    "content": "# Mount Point Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fmount_point)](https://examples.yew.rs/mount_point)\n\nThis example displays a green square followed by an input box and a field\nwhich contains the contents of the input box in reverse.\n\n## Concepts\n\n- Using the Javascript APIs with web-sys\n- Taking control of the mounting process which is usually handled by `yew::start_app`\n\n## Improvements\n\nThis example is very similar to [`two_apps`](../two_apps).\nThe two should be merged into a single example.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/mount_point/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/mount_point/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Mount Point</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/mount_point/src/main.rs",
    "content": "use wasm_bindgen::JsValue;\nuse web_sys::{\n    CanvasRenderingContext2d, Document, HtmlCanvasElement, HtmlInputElement, InputEvent,\n};\nuse yew::{html, Component, Context, Html, TargetCast};\n\npub enum Msg {\n    UpdateName(String),\n}\n\npub struct App {\n    name: String,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            name: \"Reversed\".to_owned(),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::UpdateName(new_name) => {\n                self.name = new_name;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div>\n                <input\n                    value={self.name.clone()}\n                    oninput={ctx.link().callback(|e: InputEvent| {\n                        let input = e.target_unchecked_into::<HtmlInputElement>();\n                        Msg::UpdateName(input.value())\n                    })}\n                />\n                <p>{ self.name.chars().rev().collect::<String>() }</p>\n            </div>\n        }\n    }\n}\n\nfn create_canvas(document: &Document) -> HtmlCanvasElement {\n    let canvas = HtmlCanvasElement::from(JsValue::from(document.create_element(\"canvas\").unwrap()));\n    canvas.set_width(100);\n    canvas.set_height(100);\n    let ctx =\n        CanvasRenderingContext2d::from(JsValue::from(canvas.get_context(\"2d\").unwrap().unwrap()));\n    ctx.set_fill_style_str(\"green\");\n    ctx.fill_rect(10., 10., 50., 50.);\n\n    canvas\n}\n\nfn main() {\n    let document = gloo::utils::document();\n    let body = document.query_selector(\"body\").unwrap().unwrap();\n\n    let canvas = create_canvas(&document);\n    // This canvas won't be overwritten by yew!\n    body.append_child(&canvas).unwrap();\n\n    let mount_point = document.create_element(\"div\").unwrap();\n    let class_list = mount_point.class_list();\n    class_list.add_1(\"mount-point\").unwrap();\n\n    body.append_child(&mount_point).unwrap();\n\n    yew::Renderer::<App>::with_root(mount_point).render();\n}\n"
  },
  {
    "path": "examples/nested_list/Cargo.toml",
    "content": "[package]\nname = \"nested_list\"\nversion = \"0.1.0\"\nauthors = [\"Justin Starry <justin.starry@icloud.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nimplicit-clone = { workspace = true }\nlog.workspace = true\nwasm-logger.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/nested_list/README.md",
    "content": "# Nested List Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fnested_list)](https://examples.yew.rs/nested_list)\n\nThis example shows a nested list and displays which item was last hovered.\n\n## Concepts\n\n- Creating components which only accepts specific child elements\n- Communicating with a component that isn't a parent. See `WeakComponentLink` in [main.rs](src/main.rs).\n\n## Improvements\n\n- `ListItem` Component has a `hide` prop which is currently only used statically.\n  It should be possible to make the hidden items visible by pressing a button.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/nested_list/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/nested_list/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Nested List</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"styles.scss\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/nested_list/src/app.rs",
    "content": "use std::iter;\n\nuse yew::prelude::*;\n\nuse super::header::ListHeader;\nuse super::item::ListItem;\nuse super::list::List;\nuse super::{Hovered, WeakComponentLink};\n\npub enum Msg {\n    Hover(Hovered),\n}\n\npub struct App {\n    hovered: Hovered,\n    list_link: WeakComponentLink<List>,\n    sub_list_link: WeakComponentLink<List>,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            hovered: Hovered::None,\n            list_link: WeakComponentLink::default(),\n            sub_list_link: WeakComponentLink::default(),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Hover(hovered) => {\n                self.hovered = hovered;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let on_hover = &ctx.link().callback(Msg::Hover);\n        let onmouseover = &ctx.link().callback(|_| Msg::Hover(Hovered::None));\n        let onmouseoversublist = &ctx.link().callback(|e: MouseEvent| {\n            e.stop_propagation();\n            Msg::Hover(Hovered::List)\n        });\n        let list_link = &self.list_link;\n        let sub_list_link = &self.sub_list_link;\n\n        // note the use of `html_nested!` instead of `html!`.\n        let letters = ('A'..='C')\n            .map(|letter| html_nested! { <ListItem key={format!(\"letter-{}\", letter)} name={letter.to_string()} {on_hover} /> });\n\n        html! {\n            <div class=\"main\" {onmouseover}>\n                <h1>{ \"Nested List Demo\" }</h1>\n                <List\n                    {on_hover}\n                    weak_link={list_link}\n                    header={\n                        vec![\n                            html_nested! {\n                                <ListHeader text=\"Calling all Rusties!\" {on_hover} {list_link} key=\"header\" />\n                            }\n                        ]\n                    }\n                >\n                    {vec![\n                        html_nested! { <ListItem key=\"rustin\" name=\"Rustin\" {on_hover} /> },\n                        html_nested! { <ListItem key=\"rustaroo\" hide=true name=\"Rustaroo\" {on_hover} /> },\n                        html_nested! {\n                            <ListItem key=\"rustifer\" name=\"Rustifer\" {on_hover}>\n                                <div class=\"sublist\" onmouseover={onmouseoversublist}>{ \"Sublist!\" }</div>\n                                <List\n                                    {on_hover}\n                                    weak_link={sub_list_link}\n                                    header={\n                                        vec![html_nested! {\n                                            <ListHeader key=\"sub-rusties\" text=\"Sub Rusties!\" {on_hover} list_link={sub_list_link}/>\n                                        }]\n                                    }\n                                >\n                                    {\n                                        iter::once(html_nested! { <ListItem key=\"hidden-sub\" hide=true name=\"Hidden Sub\" {on_hover} /> })\n                                        .chain(letters)\n                                        .collect::<Vec<_>>()\n                                    }\n                                </List>\n                            </ListItem>\n                        },\n                    ]}\n\n\n                </List>\n                { self.view_last_hovered() }\n            </div>\n        }\n    }\n}\n\nimpl App {\n    fn view_last_hovered(&self) -> Html {\n        html! {\n            <div class=\"last-hovered\">\n                { \"Last hovered:\"}\n                <span class=\"last-hovered-text\">\n                    { &self.hovered }\n                </span>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/nested_list/src/header.rs",
    "content": "use yew::prelude::*;\n\nuse super::list::{List, Msg as ListMsg};\nuse super::{Hovered, WeakComponentLink};\n\n#[derive(Clone, PartialEq, Properties)]\npub struct Props {\n    pub on_hover: Callback<Hovered>,\n    pub text: String,\n    pub list_link: WeakComponentLink<List>,\n}\n\npub struct ListHeader;\n\nimpl Component for ListHeader {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let list_link = ctx.props().list_link.borrow().clone().unwrap();\n        let onmouseover = ctx.props().on_hover.reform(|e: MouseEvent| {\n            e.stop_propagation();\n            Hovered::Header\n        });\n\n        html! {\n            <div\n                class=\"list-header\"\n                {onmouseover}\n                onclick={list_link.callback(|_| ListMsg::HeaderClick)}\n            >\n                { &ctx.props().text }\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/nested_list/src/item.rs",
    "content": "use yew::prelude::*;\n\nuse crate::Hovered;\n\n#[derive(PartialEq, Clone, Properties)]\npub struct Props {\n    #[prop_or_default]\n    pub hide: bool,\n    pub on_hover: Callback<Hovered>,\n    pub name: AttrValue,\n    #[prop_or_default]\n    pub children: Children,\n}\n\npub struct ListItem;\n\nimpl Component for ListItem {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onmouseover = {\n            let name = ctx.props().name.clone();\n            ctx.props().on_hover.reform(move |e: MouseEvent| {\n                e.stop_propagation();\n                Hovered::Item(name.clone())\n            })\n        };\n        html! {\n            <div class=\"list-item\" {onmouseover}>\n                { &ctx.props().name }\n                { Self::view_details(&ctx.props().children) }\n            </div>\n        }\n    }\n}\n\nimpl ListItem {\n    fn view_details(children: &Children) -> Html {\n        if children.is_empty() {\n            html! {}\n        } else {\n            html! {\n                <div class=\"list-item-details\">\n                    { children.clone() }\n                </div>\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/nested_list/src/list.rs",
    "content": "use implicit_clone::unsync::IArray;\nuse yew::prelude::*;\nuse yew::virtual_dom::VChild;\n\nuse crate::header::ListHeader;\nuse crate::item::ListItem;\nuse crate::{Hovered, WeakComponentLink};\n\npub enum Msg {\n    HeaderClick,\n}\n\n#[derive(Clone, PartialEq, Properties)]\npub struct Props {\n    #[prop_or_default]\n    pub header: IArray<VChild<ListHeader>>,\n    #[prop_or_default]\n    pub children: IArray<VChild<ListItem>>,\n\n    pub on_hover: Callback<Hovered>,\n    pub weak_link: WeakComponentLink<List>,\n}\n\npub struct List {\n    inactive: bool,\n}\n\nimpl Component for List {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        ctx.props()\n            .weak_link\n            .borrow_mut()\n            .replace(ctx.link().clone());\n        Self { inactive: false }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::HeaderClick => {\n                self.inactive = !self.inactive;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let inactive = if self.inactive { \"inactive\" } else { \"\" };\n        let onmouseover = ctx.props().on_hover.reform(|e: MouseEvent| {\n            e.stop_propagation();\n            Hovered::List\n        });\n        html! {\n            <div class=\"list-container\" {onmouseover}>\n                <div class={classes!(\"list\", inactive)}>\n                    { &ctx.props().header }\n                    <div class=\"items\">\n                        { Self::view_items(&ctx.props().children) }\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n\nimpl List {\n    fn view_items(children: &IArray<VChild<ListItem>>) -> Html {\n        children\n            .iter()\n            .filter(|c| !c.props.hide)\n            .cloned()\n            .enumerate()\n            .map(|(i, mut c)| {\n                let props = c.get_mut();\n                props.name = format!(\"#{} - {}\", i + 1, props.name).into();\n                c\n            })\n            .collect::<Html>()\n    }\n}\n"
  },
  {
    "path": "examples/nested_list/src/main.rs",
    "content": "mod app;\nmod header;\nmod item;\nmod list;\n\nuse std::cell::RefCell;\nuse std::fmt;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse yew::html::{ImplicitClone, IntoPropValue, Scope};\nuse yew::prelude::*;\n\npub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>);\n\nimpl<COMP: Component> Clone for WeakComponentLink<COMP> {\n    fn clone(&self) -> Self {\n        Self(Rc::clone(&self.0))\n    }\n}\nimpl<COMP: Component> ImplicitClone for WeakComponentLink<COMP> {}\n\nimpl<COMP: Component> Default for WeakComponentLink<COMP> {\n    fn default() -> Self {\n        Self(Rc::default())\n    }\n}\n\nimpl<COMP: Component> Deref for WeakComponentLink<COMP> {\n    type Target = Rc<RefCell<Option<Scope<COMP>>>>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<COMP: Component> PartialEq for WeakComponentLink<COMP> {\n    fn eq(&self, other: &Self) -> bool {\n        Rc::ptr_eq(&self.0, &other.0)\n    }\n}\n\n#[derive(Debug, Clone, ImplicitClone, PartialEq, Eq, Hash)]\npub enum Hovered {\n    Header,\n    Item(AttrValue),\n    List,\n    None,\n}\n\nimpl fmt::Display for Hovered {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(\n            f,\n            \"{}\",\n            match self {\n                Hovered::Header => \"Header\",\n                Hovered::Item(name) => name,\n                Hovered::List => \"List container\",\n                Hovered::None => \"Nothing\",\n            }\n        )\n    }\n}\n\nimpl IntoPropValue<Html> for &Hovered {\n    fn into_prop_value(self) -> Html {\n        html! {<>{self.to_string()}</>}\n    }\n}\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n    yew::Renderer::<app::App>::new().render();\n}\n"
  },
  {
    "path": "examples/nested_list/styles.scss",
    "content": "html,\nbody {\n  width: 100%;\n  background: #fafafa;\n  font-family: monospace;\n}\n\n.main {\n  display: flex;\n  flex-direction: column;\n  margin-top: 40px;\n  width: 100%;\n  align-items: center;\n}\n\n.list-container {\n  margin-top: 20px;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  padding: 30px;\n  border-radius: 4px;\n  background: #eee;\n\n  &:hover {\n    background: #eaeaea;\n  }\n}\n\n.list {\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n  border-radius: 3px;\n  border: 1px solid #666;\n  min-width: 30vw;\n\n  &.inactive {\n    opacity: 0.5;\n  }\n}\n\n.list-header {\n  background: #feecaa;\n  border-bottom: 1px solid #666;\n  padding: 10px;\n  cursor: pointer;\n\n  &:hover {\n    background: #fee3a0;\n  }\n}\n\n.list-item {\n  background: white;\n  border-bottom: 1px solid #666;\n  padding: 10px;\n\n  &:hover {\n    background: #fafafa;\n  }\n\n  &:last-child {\n    border-bottom: 0px;\n  }\n\n  &-details {\n    background: #eee;\n    border: 1px solid #666;\n    border-radius: 3px;\n    margin-top: 10px;\n    padding: 10px;\n    text-align: center;\n\n    &.list-container {\n      margin-top: 0px;\n      padding: 15px;\n    }\n  }\n}\n\n.last-hovered {\n  margin-top: 20px;\n\n  &-text {\n    color: #666;\n    margin-left: 5px;\n  }\n}\n\n.sublist {\n  display: inline-block;\n  background: #fff;\n  border: 1px solid #666;\n  border-radius: 3px;\n  margin: 5px;\n  padding: 5px 20px;\n}\n"
  },
  {
    "path": "examples/node_refs/Cargo.toml",
    "content": "[package]\nname = \"node_refs\"\nversion = \"0.1.0\"\nauthors = [\"Justin Starry <justin.starry@icloud.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nweb-sys = { workspace = true, features = [\"HtmlElement\", \"HtmlInputElement\", \"Node\"] }\n"
  },
  {
    "path": "examples/node_refs/README.md",
    "content": "# Node Refs Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fnode_refs)](https://examples.yew.rs/node_refs)\n\nThis example shows two input fields which are automatically focused when hovered over.\n\n## Concepts\n\nThe example uses [Refs](https://yew.rs/docs/concepts/function-components/node-refs) to\nmanipulate the underlying DOM element directly.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/node_refs/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/node_refs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Node Refs</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"css\" href=\"./styles.css\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/node_refs/src/input.rs",
    "content": "use yew::prelude::*;\n\npub enum Msg {\n    Hover,\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_hover: Callback<()>,\n    pub placeholder: AttrValue,\n    pub input_ref: NodeRef,\n}\n\npub struct InputComponent;\n\nimpl Component for InputComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Hover => {\n                ctx.props().on_hover.emit(());\n                false\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let placeholder = ctx.props().placeholder.clone();\n        html! {\n            <input\n                ref={&ctx.props().input_ref}\n                type=\"text\"\n                class=\"input-component\"\n                placeholder={placeholder}\n                onmouseover={ctx.link().callback(|_| Msg::Hover)}\n            />\n        }\n    }\n}\n"
  },
  {
    "path": "examples/node_refs/src/main.rs",
    "content": "mod input;\n\nuse input::InputComponent;\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\npub enum Msg {\n    HoverIndex(usize),\n    Submit,\n}\n\npub struct App {\n    refs: Vec<NodeRef>,\n    focus_index: usize,\n    email_error: String,\n    password_error: String,\n}\nimpl App {\n    fn apply_focus(&self) {\n        if let Some(input) = self.refs[self.focus_index].cast::<HtmlInputElement>() {\n            input.focus().unwrap();\n        }\n    }\n}\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            focus_index: 0,\n            refs: vec![NodeRef::default(), NodeRef::default()],\n            email_error: \"\".to_string(),\n            password_error: \"\".to_string(),\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            self.apply_focus();\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::HoverIndex(index) => {\n                self.focus_index = index;\n                self.apply_focus();\n                false\n            }\n            Msg::Submit => {\n                let email = &self.refs[0];\n                let password = &self.refs[1];\n                let email_value = email.cast::<HtmlInputElement>().unwrap().value();\n                let password_value = password.cast::<HtmlInputElement>().unwrap().value();\n\n                self.email_error.clear();\n                self.password_error.clear();\n\n                if !(email_value.contains('@') && email_value.contains('.')) {\n                    self.email_error.push_str(\"Invalid email.\")\n                }\n                if password_value.len() < 8 {\n                    self.password_error\n                        .push_str(\"Password must be at least 8 characters long.\")\n                }\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"main\">\n                <div id=\"left-pane\">\n                    <div>\n                        <h1>{\"Create your account\"}</h1>\n                        <div class=\"input-container\">\n                            <label>{ \"Email\" }</label>\n                            <input\n                                type=\"text\"\n                                ref={&self.refs[0]}\n                                class=\"input-element\"\n                                onmouseover={ctx.link().callback(|_| Msg::HoverIndex(0))}\n                                placeholder=\"abcd@xyz.com\"\n                            />\n                            <div class=\"error\">{self.email_error.clone()}</div>\n                        </div>\n                        <div class=\"input-container\">\n                            <label>{ \"Password\" }</label>\n                            <InputComponent\n                                input_ref={&self.refs[1]}\n                                on_hover={ctx.link().callback(|_| Msg::HoverIndex(1))}\n                                placeholder=\"password\"\n                            />\n                            <div class=\"error\">{self.password_error.clone()}</div>\n                        </div>\n                        <button onclick={ctx.link().callback(|_| Msg::Submit)}>{\"Create\"}</button>\n                    </div>\n                </div>\n                <div id=\"right-pane\">\n                    <div>\n                        <div id=\"graphic\"></div>\n                        <h1>{ \"Node Refs Example\" }</h1>\n                        <p>{ \"Refs can be used to access and manipulate DOM elements directly\" }</p>\n                        <ul>\n                            <li>{ \"First input will focus on mount\" }</li>\n                            <li>{ \"Each input will focus on hover\" }</li>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/node_refs/styles.css",
    "content": "html,\nbody {\n  margin: 0;\n  height: 100%;\n}\n\n* {\n  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;\n  box-sizing: border-box;\n}\n\n#left-pane,\n#right-pane {\n  flex: 1;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\n#right-pane {\n  background: #f6f6ff;\n}\n\n#left-pane > div {\n  width: 50%;\n}\n\n#graphic {\n  position: relative;\n  width: 100px;\n  height: 100px;\n  margin: auto;\n  margin-bottom: 5rem;\n  background-color: #4616df;\n  transform: rotate(45deg);\n}\n\n.error {\n  color: #ee5555;\n  font-size: 1rem;\n  margin-top: 0.5rem;\n}\n\n.input-container {\n  margin-bottom: 2rem;\n}\n\n.main {\n  height: 100%;\n  display: flex;\n  justify-content: stretch;\n  align-items: center;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 0.5rem;\n  font-size: 0.85rem;\n}\n\ninput {\n  padding: 0.5rem;\n  font-size: 1rem;\n  width: 100%;\n  border-radius: 0.5rem;\n  border-color: #bbb;\n  border-width: 1px;\n  border-style: solid;\n}\n\nbutton {\n  outline: none;\n  border: none;\n  background-color: #6636ff;\n  color: #fff;\n  border-radius: 0.75rem;\n  padding: 0.75rem 1.25rem;\n  width: 100%;\n  font-size: 1rem;\n}\nbutton:hover {\n  cursor: pointer;\n}\n"
  },
  {
    "path": "examples/password_strength/Cargo.toml",
    "content": "[package]\nname = \"password_strength\"\nversion = \"0.1.0\"\nauthors = [\"Philip Peterson <pc.peterso@gmail.com>\"]\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nzxcvbn = \"3.1.0\"\njs-sys.workspace = true\nweb-sys = { workspace = true, features = [\"Event\",\"EventTarget\",\"InputEvent\"] }\nwasm-bindgen.workspace = true\nchrono = { workspace = true, features = [\"wasmbind\"] }\n"
  },
  {
    "path": "examples/password_strength/README.md",
    "content": "# Password Strength Estimator Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fpassword_strength)](https://examples.yew.rs/password_strength)\n\nA password strength estimator implemented in Yew.\n\n### Notes\n\nIf this example is a bit slow, you should try running it with the `release` profile.\n\n## Concepts\n\nThis example\n\n- makes use of controlled components.\n- extracts new value from `InputEvent`\n- calls out to `js_sys` to invoke a foreign function, `Math.random()`\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/password_strength/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/password_strength/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Password Strength Estimator</title>\n\n    <link data-trunk rel=\"rust\" />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/password_strength/index.scss",
    "content": "html,\nbody {\n  height: 100%;\n  margin: 0;\n}\n\nbody {\n  align-items: center;\n  display: flex;\n  justify-content: center;\n  color: rgba(0, 0, 0, 0.7);\n\n  background: linear-gradient(to bottom right, #00d034, #c0c0c0);\n  font-size: 1.5rem;\n  font-family: sans-serif;\n}\n\nmain {\n  width: 30em;\n}\n\n.entry,\n.readout {\n  margin: 0 auto;\n  padding: 8px;\n  border: 1px solid black;\n  background-color: rgba(0, 0, 0, 0.25);\n}\n\n.entry input {\n  font-size: 1.5rem;\n  background: transparent;\n  border: 1px solid rgba(0, 0, 0, 0.6);\n  width: 100%;\n  display: block;\n  box-sizing: border-box;\n  margin-top: 16px;\n}\n\n.readout {\n  margin-top: 16px;\n}\n\ninput:focus {\n  outline: 0;\n  border-color: #550096;\n}\n\n.footnote {\n  font-size: 0.9rem;\n  margin-top: 16px;\n}\n"
  },
  {
    "path": "examples/password_strength/src/app.rs",
    "content": "extern crate zxcvbn;\n\nuse yew::prelude::*;\nuse zxcvbn::zxcvbn;\n\nuse crate::password::generate_password;\nuse crate::text_input::TextInput;\n\npub enum Msg {\n    SetPassword(String),\n    RegeneratePassword,\n}\n\n#[derive(Debug, Default)]\npub struct App {\n    password: String,\n}\n\nimpl App {\n    fn get_estimate(&self) -> u8 {\n        let score = zxcvbn(&self.password, &[]).score();\n        score.into()\n    }\n\n    fn redout_top_row_text(&self) -> String {\n        if self.password.is_empty() {\n            return \"Provide a password\".to_string();\n        }\n        let estimate_text = match self.get_estimate() {\n            0 => \"That's a password?\",\n            1 => \"You can do a lot better.\",\n            2 => \"Meh\",\n            3 => \"Good\",\n            _ => \"Great!\",\n        };\n        format!(\"Complexity = {estimate_text}\")\n    }\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self::default()\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetPassword(next_password) => self.password = next_password,\n            Msg::RegeneratePassword => self.password = generate_password(),\n        };\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let on_change = ctx.link().callback(Msg::SetPassword);\n        let onclick = ctx.link().callback(|_| Msg::RegeneratePassword);\n        html! {\n            <main>\n                <div class=\"entry\">\n                    <div>\n                        {\"Enter a password below:\"}\n                        <div class=\"footnote\">\n                            {\"(Will show in clear text)\"}\n                        </div>\n                    </div>\n                    <div>\n                        <TextInput {on_change} value={self.password.clone()} />\n                    </div>\n                </div>\n                <div class=\"readout\">\n                    <div>\n                        {self.redout_top_row_text()}\n                    </div>\n                    <button {onclick}>\n                        {\"Generate new password *\"}\n                    </button>\n                    <div class=\"footnote\">\n                        {\"* Note: generated passwords are not actually cryptographically secure\"}\n                    </div>\n                </div>\n            </main>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/password_strength/src/main.rs",
    "content": "#![recursion_limit = \"256\"]\n\nmod text_input;\n\nmod app;\nmod password;\n\nuse app::App;\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/password_strength/src/password.rs",
    "content": "const PASSWORD_LEN: i32 = 17;\n\npub fn generate_password() -> String {\n    let mut space: Vec<char> = vec![];\n    for c in 'a'..='z' {\n        space.push(c);\n    }\n    for c in 'A'..='Z' {\n        space.push(c);\n    }\n    for c in '0'..='9' {\n        space.push(c);\n    }\n    space.extend(\n        [\n            '_', ']', '[', '.', '-', '+', '=', ':', ';', '/', '?', '<', '>', '\\\\', '*', '&', '^',\n            '%', '$', '#', '@', '!', '`', '~', ',',\n        ]\n        .iter(),\n    );\n    let mut result = \"\".to_string();\n    for _ in 0..PASSWORD_LEN {\n        let i = (js_sys::Math::random() * space.len() as f64).floor() as usize;\n        result.push(space[i]);\n    }\n    result\n}\n"
  },
  {
    "path": "examples/password_strength/src/text_input.rs",
    "content": "use wasm_bindgen::{JsCast, UnwrapThrowExt};\nuse web_sys::{Event, HtmlInputElement, InputEvent};\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct Props {\n    pub value: String,\n    pub on_change: Callback<String>,\n}\n\nfn get_value_from_input_event(e: InputEvent) -> String {\n    let event: Event = e.dyn_into().unwrap_throw();\n    let event_target = event.target().unwrap_throw();\n    let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();\n    web_sys::console::log_1(&target.value().into());\n    target.value()\n}\n\n/// Controlled Text Input Component\n#[function_component(TextInput)]\npub fn text_input(props: &Props) -> Html {\n    let Props { value, on_change } = props.clone();\n\n    let oninput = Callback::from(move |input_event: InputEvent| {\n        on_change.emit(get_value_from_input_event(input_event));\n    });\n\n    html! {\n        <input type=\"text\" {value} {oninput} />\n    }\n}\n"
  },
  {
    "path": "examples/portals/Cargo.toml",
    "content": "[package]\nname = \"portals\"\nversion = \"0.1.0\"\nauthors = [\"Martin Molzer <worldsbegin@gmx.de>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\nwasm-bindgen.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"Document\",\n    \"Element\",\n    \"Node\",\n    \"HtmlHeadElement\",\n    \"ShadowRoot\",\n    \"ShadowRootInit\",\n    \"ShadowRootMode\",\n]\n"
  },
  {
    "path": "examples/portals/README.md",
    "content": "# Portals Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fportals)](https://examples.yew.rs/portals)\n\nThis example renders elements into out-of-tree nodes with the help of portals.\n\n## Concepts\n\n- Manually creating `Html` without the `html!` macro.\n- Using `web-sys` to manipulate the DOM.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/portals/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/portals/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Portals</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/portals/src/main.rs",
    "content": "use wasm_bindgen::JsCast;\nuse web_sys::{Element, ShadowRootInit, ShadowRootMode};\nuse yew::{create_portal, html, Component, Context, Html, NodeRef, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ShadowDOMProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct ShadowDOMHost {\n    host_ref: NodeRef,\n    inner_host: Option<Element>,\n}\n\nimpl Component for ShadowDOMHost {\n    type Message = ();\n    type Properties = ShadowDOMProps;\n\n    fn create(_: &Context<Self>) -> Self {\n        Self {\n            host_ref: NodeRef::default(),\n            inner_host: None,\n        }\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            let shadow_root = self\n                .host_ref\n                .get()\n                .expect(\"rendered host\")\n                .unchecked_into::<Element>()\n                .attach_shadow(&ShadowRootInit::new(ShadowRootMode::Open))\n                .expect(\"installing shadow root succeeds\");\n            let inner_host = gloo::utils::document()\n                .create_element(\"div\")\n                .expect(\"can create inner wrapper\");\n            shadow_root\n                .append_child(&inner_host)\n                .expect(\"can attach inner host\");\n            self.inner_host = Some(inner_host);\n            ctx.link().send_message(());\n        }\n    }\n\n    fn update(&mut self, _: &Context<Self>, _: Self::Message) -> bool {\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let contents = if let Some(ref inner_host) = self.inner_host {\n            create_portal(ctx.props().children.clone(), inner_host.clone())\n        } else {\n            html! { <></> }\n        };\n        html! {\n            <div ref={self.host_ref.clone()}>\n                {contents}\n            </div>\n        }\n    }\n}\n\npub struct App {\n    style_html: Html,\n    title_element: Element,\n    counter: u32,\n}\n\npub enum AppMessage {\n    IncreaseCounter,\n}\n\nimpl Component for App {\n    type Message = AppMessage;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        let document_head = gloo::utils::document()\n            .head()\n            .expect(\"head element to be present\");\n        let title_element = document_head\n            .query_selector(\"title\")\n            .expect(\"to find a title element\")\n            .expect(\"to find a title element\");\n        title_element.set_text_content(None); // Clear the title element\n        let style_html = create_portal(\n            html! {\n                <style>{\"p { color: red; }\"}</style>\n            },\n            document_head.into(),\n        );\n        Self {\n            style_html,\n            title_element,\n            counter: 0,\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            AppMessage::IncreaseCounter => self.counter += 1,\n        }\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| AppMessage::IncreaseCounter);\n        let title = create_portal(\n            html! {\n                if self.counter > 0 {\n                    {format!(\"Clicked {} times\", self.counter)}\n                } else {\n                    {\"Yew • Portals\"}\n                }\n            },\n            self.title_element.clone(),\n        );\n        html! {\n            <>\n            {self.style_html.clone()}\n            {title}\n            <p>{\"This paragraph is colored red, and its style is mounted into \"}<pre>{\"document.head\"}</pre>{\" with a portal\"}</p>\n            <div>\n                <ShadowDOMHost>\n                    <p>{\"This paragraph is rendered in a shadow dom and thus not affected by the surrounding styling context\"}</p>\n                    <span>{\"Buttons clicked inside the shadow dom work fine.\"}</span>\n                    <button {onclick}>{\"Click me!\"}</button>\n                </ShadowDOMHost>\n                <p>{format!(\"The button has been clicked {} times. This is also reflected in the title of the tab!\", self.counter)}</p>\n            </div>\n            </>\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/router/Cargo.toml",
    "content": "[package]\nname = \"router\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nfunction_router = { path = \"../function_router\" }\ninstant = { workspace = true }\nlipsum = { version = \"0.9.1\", git = \"https://github.com/mgeisler/lipsum.git\", rev = \"233e48a\" }\nlog.workspace = true\ngetrandom = { workspace = true }\nrand = { workspace = true, features = [\"small_rng\"] }\nwasm-logger.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nyew-router = { path = \"../../packages/yew-router\" }\nserde = { workspace = true, features = [\"derive\"] }\ngloo.workspace = true\n"
  },
  {
    "path": "examples/router/README.md",
    "content": "# Router Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Frouter)](https://examples.yew.rs/router)\n\nA blog all about yew.\nThe best way to figure out what this example is about is to just open it up.\nIt's mobile friendly too!\n\n## Concepts\n\nThis example involves many different parts, here are just the Yew specific things:\n\n- Uses [`yew-router`] to render and switch between multiple pages.\n\nThe example automatically adapts to the `--public-url` value passed to Trunk.\nThis allows it to be hosted on any path, not just at the root.\nFor example, our demo is hosted at [/router](https://examples.yew.rs/router).\n\nThis is achieved by adding `<base data-trunk-public-url />` to the [index.html](index.html) file.\nTrunk rewrites this tag to contain the value passed to `--public-url` which can then be retrieved at runtime.\nTake a look at [`Route`](src/main.rs) for the implementation.\n\n## Improvements\n\n- Use a special image component which shows a progress bar until the image is loaded.\n- Scroll back to the top after switching route\n- Run content generation in a dedicated web worker\n- Use longer Markov chains to achieve more coherent results\n- Make images deterministic (the same seed should produce the same images)\n- Show posts by the author on their page\n  (this is currently impossible because we need to find post seeds which in turn generate the author's seed)\n- Show other posts at the end of a post (\"continue reading\")\n- Home (`/`) should include links to the post list and the author introduction\n- Detect sub-path from `--public-url` value passed to Trunk. See: thedodd/trunk#51\n\n[`yew-router`]: https://docs.rs/yew-router/latest/yew_router/\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```\n\n### Notes\n\nContent generation can take up quite a bit of time in debug builds. If it is too slow, you should try running with the `release` profile."
  },
  {
    "path": "examples/router/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/router/data/keywords.txt",
    "content": "allergenics\narchaeology\naustria\nberries\nbirds\ncolor\nconservation\ncosmology\nculture\neurope\nevergreens\nfleshy\nfrance\nguides\nhorticulture\nireland\nlandscaping\nmedicine\nmusic\npoison\nreligion\nrome\nrust\nscotland\nseeds\nspain\ntaxonomy\ntoxics\ntradition\ntrees\nwasm\nwood\nwoodworking\nyew\n"
  },
  {
    "path": "examples/router/data/syllables.txt",
    "content": "ald\nber\nfe\nger\njo\njus\nkas\nlix\nlu\nmon\nmour\nnas\nridge\nry\nsi\nstar\ntey\ntim\ntin\nyew\n"
  },
  {
    "path": "examples/router/data/yew.txt",
    "content": "Taxonomy and naming\n\nThe word yew is from Proto-Germanic, possibly originally a loanword from Gaulish.\nIn German it is known as Eibe. Baccata is Latin for bearing berries.\nThe word yew as it was originally used seems to refer to the color brown.\nThe yew was known to Theophrastus, who noted its preference for mountain coolness and shade,\nits evergreen character and its slow growth.\n\nMost Romance languages, with the notable exception of French,\nkept a version of the Latin word taxus from the same root as toxic.\nIn Slavic languages, the same root is preserved.\n\nIn Iran, the tree is known as sorkhdār.\n\nThe common yew was one of the many species first described by Linnaeus.\nIt is one of around 30 conifer species in seven genera in the family Taxaceae, which is placed in the order Pinales.\n\n\nDescription\n\nIt is a small to medium-sized evergreen tree, growing 10 to 20 metres tall, with a trunk up to 2 metres in diameter.\nThe bark is thin, scaly brown, coming off in small flakes aligned with the stem.\nThe leaves are flat, dark green, 1 to 4 centimetres long and 2 to 3 millimetres broad, arranged spirally on the stem,\nbut with the leaf bases twisted to align the leaves in two flat rows either side of the stem,\nexcept on erect leading shoots where the spiral arrangement is more obvious.\nThe leaves are poisonous.\n\nThe seed cones are modified, each cone containing a single seed, which is 4 to 7 millimetres long,\nand partly surrounded by a fleshy scale which develops into a soft, bright red berry-like structure called an aril.\nThe aril is 8 to 15 millimetres long and wide and open at the end.\nThe arils mature 6 to 9 months after pollination, and with the seed contained,\nare eaten by thrushes, waxwings and other birds, which disperse the hard seeds undamaged in their droppings.\nMaturation of the arils is spread over 2 to 3 months, increasing the chances of successful seed dispersal.\nThe seeds themselves are poisonous and bitter, but are opened and eaten by some bird species including hawfinches,\ngreenfinches and great tits.\nThe aril is not poisonous, it is gelatinous and very sweet tasting. The male cones are globose,\n3–6 millimetres in diameter, and shed their pollen in early spring.\nThe yew is mostly dioecious, but occasional individuals can be variably monoecious, or change sex with time.\n\n\nLongevity\n\nTaxus baccata can reach 400 to 600 years of age.\nSome specimens live longer but the age of yews is often overestimated.\nTen yews in Britain are believed to predate the 10th century.\nThe potential age of yews is impossible to determine accurately and is subject to much dispute.\nThere is rarely any wood as old as the entire tree, while the boughs themselves often become hollow with age,\nmaking ring counts impossible.\nEvidence based on growth rates and archaeological work of surrounding structures suggests the oldest yews,\nsuch as the Fortingall Yew in Perthshire, Scotland, may be in the range of 2,000 years,\nplacing them among the oldest plants in Europe.\nOne characteristic contributing to yew's longevity is that it is able to split under the weight of advanced growth\nwithout succumbing to disease in the fracture, as do most other trees. Another is its ability to give rise to new\nepicormic and basal shoots from cut surfaces and low on its trunk, even at an old age.\n\n\nSignificant trees\n\nThe Fortingall Yew in Perthshire, Scotland,\nhas the largest recorded trunk girth in Britain and experts estimate it to be 2,000 to 3,000 years old,\nalthough it may be a remnant of a post-Roman Christian site and around 1,500 years old.\nThe Llangernyw Yew in Clwyd, Wales, can be found at an early saint site and is about 1,500 years old.\nOther well known yews include the Ankerwycke Yew, the Balderschwang Yew, the Caesarsboom, the Florence Court Yew,\nand the Borrowdale Fraternal Four, of which poet William Wordsworth wrote.\nThe Kingley Vale National Nature Reserve in West Sussex has one of Europe's largest yew woodlands.\n\nThe oldest specimen in Spain is located in Bermiego, Asturias. It is known as Teixu l'Iglesia in the Asturian language.\nIt stands 15m tall with a trunk diameter of 7m and a crown diameter of 15m.\nIt was declared a Natural Monument on April 27,\n1995 by the Asturian Government and is protected by the Plan of Natural Resources.\n\nA unique forest formed by Taxus baccata and European box lies within the city of Sochi, in the Western Caucasus.\n\nThe oldest Irish Yew, the Florence Court Yew, still stands in the grounds of Florence Court estate in County Fermanagh,\nNorthern Ireland.\nThe Irish Yew has become ubiquitous in cemeteries across the world and it is believed that all known examples are from\ncuttings from this tree.\n\n\nToxicity\n\nThe entire yew bush, except the aril, is poisonous.\nIt is toxic due to a group of chemicals called taxine alkaloids.\nTheir cardiotoxicity is well known and act via calcium and sodium channel antagonism, causing an increase in\ncytoplasmic calcium currents of the myocardial cells.\nThe seeds contain the highest concentrations of these alkaloids. If any leaves or seeds of the plant are ingested,\nurgent medical advice is recommended as well as observation for at least 6 hours after the point of ingestion.\nThe most cardiotoxic taxine is Taxine B followed by Taxine A.\nTaxine B also happens to be the most common alkaloid in the Taxus species.\n\nYew poisonings are relatively common in both domestic and wild animals who consume the plant accidentally,\nresulting in countless fatalities in livestock.\nThe taxine alkaloids are absorbed quickly from the intestine and in high enough quantities can cause death due to\ncardiac arrest or respiratory failure.\nTaxines are also absorbed efficiently via the skin and Taxus species should thus be handled with care and preferably\nwith gloves.\nTaxus baccata leaves contain approximately 5mg of taxines per 1g of leaves.\n\nThe estimated lethal dose of taxine alkaloids is approximately 3.0mg/kg body weight for humans.\nThe lethal dose for an adult is reported to be 50g of yew needles.\nPatients who ingest a lethal dose frequently die due to cardiogenic shock, in spite of resuscitation efforts.\nThere are currently no known antidotes for yew poisoning,\nbut drugs such as atropine have been used to treat the symptoms.\nTaxine remains in the plant all year, with maximal concentrations appearing during the winter.\nDried yew plant material retains its toxicity for several months and even increases its toxicity as the water is removed.\nFallen leaves should therefore also be considered toxic.\nPoisoning usually occurs when leaves of yew trees are eaten,\nbut in at least one case a victim inhaled sawdust from a yew tree.\n\nIt is difficult to measure taxine alkaloids and this is a major reason as to why different studies show different results.\n\nSeveral studies have found taxine LD50 values under 20mg/kg in mice and rats.\n\nMale and monoecious yews in this genus release toxic pollen, which can cause the mild symptoms.\nThe pollen is also a trigger for asthma.\nThese pollen grains are only 15 microns in size, and can easily pass through most window screens.\n\n\nAllergenic potential\n\nYews in this genus are primarily separate-sexed, and males are extremely allergenic,\nwith an OPALS allergy scale rating of 10 out of 10.\nCompletely female yews have an OPALS rating of 1, and are considered allergy-fighting.\nMale yews bloom and release abundant amounts of pollen in the spring;\ncompletely female yews only trap pollen while producing none.\n\n\nUses and traditions\n\nIn the ancient Celtic world, the yew tree had extraordinary importance; a passage by Caesar narrates that Cativolcus,\nchief of the Eburones poisoned himself with yew rather than submit to Rome.\nSimilarly, Florus notes that when the Cantabrians were under siege by the legate Gaius Furnius in 22 BC,\nmost of them took their lives either by the sword, by fire, or by a poison extracted ex arboribus taxeis, that is,\nfrom the yew tree.\nIn a similar way, Orosius notes that when the Astures were besieged at Mons Medullius,\nthey preferred to die by their own swords or by the yew tree poison rather than surrender.\n\nThe word York is derived from the Brittonic name Eburākon,\na combination of eburos \"yew-tree\" and a suffix of appurtenance meaning either \"place of the yew trees\";\nor alternatively, \"the settlement of Eburos\".\n\nThe name Eboracum became the Anglian Eoforwic in the 7th century.\nWhen the Danish army conquered the city in 866, its name became Jórvík.\n\nThe Old French and Norman name of the city following the Norman Conquest was recorded as Everwic in works such as\nWace's Roman de Rou.\nJórvík, meanwhile, gradually reduced to York in the centuries after the Conquest,\nmoving from the Middle English Yerk in the 14th century through Yourke in the 16th century to Yarke in the 17th century.\nThe form York was first recorded in the 13th century. Many company and place names, such as the Ebor race meeting,\nrefer to the Latinised Brittonic, Roman name.\n\nThe 12th‑century chronicler Geoffrey of Monmouth, in his fictional account of the prehistoric kings of Britain,\nHistoria Regum Britanniae, suggests the name derives from that of a pre-Roman city founded by the legendary king Ebraucus.\n\nThe Archbishop of York uses Ebor as his surname in his signature.\n\nThe area of Ydre in the South Swedish highlands is interpreted to mean place of yews.\nTwo localities in particular, Idhult and Idebo, appear to be further associated with yews.\n\n\nReligion\n\nThe yew is traditionally and regularly found in churchyards in England, Wales, Scotland, Ireland and Northern France.\nSome examples can be found in La Haye-de-Routot or La Lande-Patry.\nIt is said up to 40 people could stand inside one of the La-Haye-de-Routot yew trees,\nand the Le Ménil-Ciboult yew is probably the largest at 13m diameter.\nYews may grow to become exceptionally large and may live to be over 2,000 years old.\nSometimes monks planted yews in the middle of their cloister, as at Muckross Abbey or abbaye de Jumièges.\nSome ancient yew trees are located at St. Mary the Virgin Church, Overton-on-Dee in Wales.\n\nIn Asturian tradition and culture, the yew tree was considered to be linked with the land, people,\nancestors and ancient religion. It was tradition on All Saints' Day to bring a branch of a yew tree to the tombs of\nthose who had died recently so they would be guided in their return to the Land of Shadows.\nThe yew tree has been found near chapels,\nchurches and cemeteries since ancient times as a symbol of the transcendence of death.\nThey are often found in the main squares of villages where people celebrated the open councils that served as a way of\ngeneral assembly to rule village affairs.\n\nIt has been suggested that the sacred tree at the Temple at Uppsala was an ancient yew tree.\nThe Christian church commonly found it expedient to take over existing pre-Christian sacred sites for churches.\nIt has also been suggested that yews were planted at religious sites as their long life was suggestive of eternity,\nor because, being toxic when ingested, they were seen as trees of death.\nAnother suggested explanation is that yews were planted to discourage farmers and drovers from letting animals wander\nonto the burial grounds, the poisonous foliage being the disincentive.\nA further possible reason is that fronds and branches of yew were often used as a substitute for palms on Palm Sunday.\n\nSome yew trees were actually native to the sites before the churches were built.\nKing Edward I of England ordered yew trees to be planted in churchyards to offer some protection to the buildings.\nYews are poisonous so by planting them in the churchyards cattle that were not allowed to graze on hallowed\nground were safe from eating yew. Yew branches touching the ground take root and sprout again;\nthis became a symbol of death, rebirth and therefore immortality.\n\nIn interpretations of Norse cosmology, the tree Yggdrasil has traditionally been interpreted as a giant ash tree.\nSome scholars now believe errors were made in past interpretations of the ancient writings,\nand that the tree is most likely a European yew.\n\nIn the Crann Ogham—the variation on the ancient Irish Ogham alphabet which consists of a list of trees—yew\nis the last in the main list of 20 trees, primarily symbolizing death.\nThere are stories of people who have committed suicide by ingesting the foliage.\nAs the ancient Celts also believed in the transmigration of the soul,\nthere is in some cases a secondary meaning of the eternal soul that survives death to be reborn in a new form.\n\n\nMedical\n\nCertain compounds found in the bark of yew trees were discovered by Wall and Wani in 1967 to have efficacy as\nanti-cancer agents.\nThe precursors of the chemotherapy drug paclitaxel were later shown to be synthesized easily from extracts\nof the leaves of European yew, which is a much more renewable source than the bark of the Pacific yew from which\nthey were initially isolated.\nThis ended a point of conflict in the early 1990s; many environmentalists,\nincluding Al Gore, had opposed the destructive harvesting of Pacific yew for paclitaxel cancer treatments.\nDocetaxel can then be obtained by semi-synthetic conversion from the precursors.\n\n\nWoodworking and longbows\n\nWood from the yew is classified as a closed-pore softwood, similar to cedar and pine.\nEasy to work, yew is among the hardest of the softwoods; yet it possesses a remarkable elasticity,\nmaking it ideal for products that require springiness, such as bows.\nDue to all parts of the yew and its volatile oils being poisonous and cardiotoxic,\na mask should be worn if one comes in contact with sawdust from the wood.\n\nOne of the world's oldest surviving wooden artifacts is a Clactonian yew spear head, found in 1911 at Clacton-on-Sea,\nin Essex, UK. Known as the Clacton Spear, it is estimated to be over 400,000 years old.\n\nYew is also associated with Wales and England because of the longbow,\nan early weapon of war developed in northern Europe,\nand as the English longbow the basis for a medieval tactical system.\nThe oldest surviving yew longbow was found at Rotten Bottom in Dumfries and Galloway, Scotland.\nIt has been given a calibrated radiocarbon date of 4040 BC to 3640 BC and is on display in the National Museum of\nScotland. Yew is the wood of choice for longbow making;\nthe heartwood is always on the inside of the bow with the sapwood on the outside.\nThis makes most efficient use of their properties as heartwood is best in compression whilst\nsapwood is superior in tension.\nHowever, much yew is knotty and twisted, and therefore unsuitable for bowmaking;\nmost trunks do not give good staves and even in a good trunk much wood has to be discarded.\n\nThere was a tradition of planting yew trees in churchyards throughout Britain and Ireland, among other reasons,\nas a resource for bows. \nArdchattan Priory whose yew trees, according to other accounts,\nwere inspected by Robert the Bruce and cut to make at least some of the longbows used at the Battle of Bannockburn.\n\nThe trade of yew wood to England for longbows was so robust that it depleted the stocks of good-quality,\nmature yew over a vast area.\nThe first documented import of yew bowstaves to England was in 1294.\nIn 1423 the Polish king commanded protection of yews in order to cut exports,\nfacing nearly complete destruction of local yew stock. In 1470 compulsory archery practice was renewed, and hazel, ash,\nand laburnum were specifically allowed for practice bows.\nSupplies still proved insufficient, until by the Statute of Westminster in 1472,\nevery ship coming to an English port had to bring four bowstaves for every tun.\nRichard III of England increased this to ten for every tun. This stimulated a vast network of extraction and supply,\nwhich formed part of royal monopolies in southern Germany and Austria.\nIn 1483, the price of bowstaves rose from two to eight pounds per hundred,\nand in 1510 the Venetians would only sell a hundred for sixteen pounds.\nIn 1507 the Holy Roman Emperor asked the Duke of Bavaria to stop cutting yew, but the trade was profitable,\nand in 1532 the royal monopoly was granted for the usual quantity if there are that many.\nIn 1562, the Bavarian government sent a long plea to the Holy Roman Emperor asking him to stop the cutting of yew,\nand outlining the damage done to the forests by its selective extraction,\nwhich broke the canopy and allowed wind to destroy neighbouring trees. In 1568, despite a request from Saxony,\nno royal monopoly was granted because there was no yew to cut,\nand the next year Bavaria and Austria similarly failed to produce enough yew to justify a royal monopoly.\nForestry records in this area in the 17th century do not mention yew, and it seems that no mature trees were to be had.\nThe English tried to obtain supplies from the Baltic, but at this period bows were being replaced by guns in any case.\n\n\nHorticulture\n\nToday European yew is widely used in landscaping and ornamental horticulture.\nDue to its dense, dark green, mature foliage, and its tolerance of even very severe pruning,\nit is used especially for formal hedges and topiary.\nIts relatively slow growth rate means that in such situations it needs to be clipped only once per year.\n\nWell over 200 cultivars of T. baccata have been named. The most popular of these are the Irish yew,\na fastigiate cultivar of the European yew selected from two trees found growing in Ireland,\nand the several cultivars with yellow leaves, collectively known as golden yew. In some locations,\nwhen hemmed in by buildings or other trees,\nan Irish yew can reach 20 feet in height without exceeding 2 feet in diameter at its thickest point,\nalthough with age many Irish yews assume a fat cigar shape rather than being truly columnar.\n\nEuropean yew will tolerate growing in a wide range of soils and situations, including shallow chalk soils and shade,\nalthough in deep shade its foliage may be less dense.\nHowever it cannot tolerate waterlogging,\nand in poorly-draining situations is liable to succumb to the root-rotting pathogen Phytophthora cinnamomi.\n\nIn Europe, Taxus baccata grows naturally north to Molde in southern Norway, but it is used in gardens further north.\nIt is also popular as a bonsai in many parts of Europe and makes a handsome small- to large-sized bonsai.\n\n\nPrivies\n\nIn England, yew has historically been sometimes associated with privies,\npossibly because the smell of the plant keeps insects away.\n\n\nMusical instruments\n\nThe late Robert Lundberg, a noted luthier who performed extensive research on historical lute-making methodology,\nstates in his 2002 book Historical Lute Construction that yew was historically a prized wood for lute construction.\nEuropean legislation establishing use limits and requirements for yew limited supplies available to luthiers,\nbut it was apparently as prized among medieval, renaissance,\nand baroque lute builders as Brazilian rosewood is among contemporary guitar-makers for its quality of sound and beauty.\n\n\nConservation\n\nClippings from ancient specimens in the UK, including the Fortingall Yew,\nwere taken to the Royal Botanic Gardens in Edinburgh to form a mile-long hedge.\nThe purpose of this project is to maintain the DNA of Taxus baccata.\nThe species is threatened by felling, partly due to rising demand from pharmaceutical companies, and disease.\n\nAnother conservation programme was run in Catalonia in the early 2010s, by the Forest Sciences Centre of Catalonia,\nin order to protect genetically endemic yew populations, and preserve them from overgrazing and forest fires.\nIn the framework of this programme, the 4th International Yew Conference was organised in the Poblet Monastery in 2014,\nwhich proceedings are available.\n\nThere has also been a conservation programme in northern Portugal and Northern Spain.\n"
  },
  {
    "path": "examples/router/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>Yew • Router</title>\n    <base data-trunk-public-url />\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css\"\n    />\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/router/index.scss",
    "content": ".hero {\n  &.has-background {\n    position: relative;\n    overflow: hidden;\n  }\n\n  &-background {\n    position: absolute;\n    object-fit: cover;\n    object-position: bottom;\n    width: 100%;\n    height: 100%;\n\n    &.is-transparent {\n      opacity: 0.3;\n    }\n  }\n}\n\n.burger {\n  background-color: transparent;\n  border: none;\n}\n\n.navbar-brand {\n  align-items: center;\n}\n"
  },
  {
    "path": "examples/router/src/components/author_card.rs",
    "content": "use yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::content::Author;\nuse crate::generator::Generated;\nuse crate::Route;\n\n#[derive(Clone, Debug, PartialEq, Eq, Properties)]\npub struct Props {\n    pub seed: u64,\n}\n\npub struct AuthorCard {\n    author: Author,\n}\nimpl Component for AuthorCard {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self {\n            author: Author::generate_from_seed(ctx.props().seed),\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n        self.author = Author::generate_from_seed(ctx.props().seed);\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let Self { author } = self;\n        html! {\n            <div class=\"card\">\n                <div class=\"card-content\">\n                    <div class=\"media\">\n                        <div class=\"media-left\">\n                            <figure class=\"image is-128x128\">\n                                <img alt=\"Author's profile picture\" src={author.image_url.clone()} />\n                            </figure>\n                        </div>\n                        <div class=\"media-content\">\n                            <p class=\"title is-3\">{ &author.name }</p>\n                            <p>\n                                { \"I like \" }\n                                <b>{ author.keywords.join(\", \") }</b>\n                            </p>\n                        </div>\n                    </div>\n                </div>\n                <footer class=\"card-footer\">\n                    <Link<Route> classes={classes!(\"card-footer-item\")} to={Route::Author { id: author.seed }}>\n                        { \"Profile\" }\n                    </Link<Route>>\n                </footer>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/components/mod.rs",
    "content": "pub mod author_card;\npub mod pagination;\npub mod post_card;\npub mod progress_delay;\n"
  },
  {
    "path": "examples/router/src/components/pagination.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::Route;\n\nconst ELLIPSIS: &str = \"\\u{02026}\";\n\n#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]\npub struct PageQuery {\n    pub page: u64,\n}\n\n#[derive(Clone, Debug, PartialEq, Eq, Properties)]\npub struct Props {\n    pub page: u64,\n    pub total_pages: u64,\n    pub route_to_page: Route,\n}\n\npub struct Pagination;\n\nimpl Component for Pagination {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <nav class=\"pagination is-right\" role=\"navigation\" aria-label=\"pagination\">\n                { self.view_relnav_buttons(ctx.props()) }\n                <ul class=\"pagination-list\">\n                    { self.view_links(ctx.props()) }\n                </ul>\n            </nav>\n        }\n    }\n}\nimpl Pagination {\n    fn render_link(&self, to_page: u64, props: &Props) -> Html {\n        let Props {\n            page,\n            route_to_page,\n            ..\n        } = props.clone();\n\n        let is_current_class = if to_page == page { \"is-current\" } else { \"\" };\n\n        html! {\n            <li>\n                <Link<Route, PageQuery>\n                    classes={classes!(\"pagination-link\", is_current_class)}\n                    to={route_to_page}\n                    query={Some(PageQuery{page: to_page})}\n                >\n                    { to_page }\n                </Link<Route, PageQuery>>\n            </li>\n        }\n    }\n\n    fn render_links<P>(&self, mut pages: P, len: usize, max_links: usize, props: &Props) -> Html\n    where\n        P: Iterator<Item = u64> + DoubleEndedIterator,\n    {\n        if len > max_links {\n            let last_link = self.render_link(pages.next_back().unwrap(), props);\n            // remove 1 for the ellipsis and 1 for the last link\n            let links = pages\n                .take(max_links - 2)\n                .map(|page| self.render_link(page, props));\n            html! {\n                <>\n                    { for links }\n                    <li><span class=\"pagination-ellipsis\">{ ELLIPSIS }</span></li>\n                    { last_link }\n                </>\n            }\n        } else {\n            html! {\n                for page in pages {\n                    {self.render_link(page, props)}\n                }\n            }\n        }\n    }\n\n    fn view_links(&self, props: &Props) -> Html {\n        const LINKS_PER_SIDE: usize = 3;\n\n        let Props {\n            page, total_pages, ..\n        } = *props;\n\n        let pages_prev = page.saturating_sub(1) as usize;\n        let pages_next = (total_pages - page) as usize;\n\n        let links_left = LINKS_PER_SIDE.min(pages_prev)\n            // if there are less than `LINKS_PER_SIDE` to the right, we add some more on the left.\n            + LINKS_PER_SIDE.saturating_sub(pages_next);\n        let links_right = 2 * LINKS_PER_SIDE - links_left;\n\n        html! {\n            <>\n                { self.render_links(1..page, pages_prev, links_left, props) }\n                <li>{ self.render_link(page, props) }</li>\n                { self.render_links(page + 1..=total_pages, pages_next, links_right, props) }\n            </>\n        }\n    }\n\n    fn view_relnav_buttons(&self, props: &Props) -> Html {\n        let Props {\n            page,\n            total_pages,\n            route_to_page: to,\n        } = props.clone();\n\n        html! {\n            <>\n                <Link<Route, PageQuery>\n                    classes={classes!(\"pagination-previous\")}\n                    disabled={page==1}\n                    query={Some(PageQuery{page: page - 1})}\n                    to={to.clone()}\n                >\n                    { \"Previous\" }\n                </Link<Route, PageQuery>>\n                <Link<Route, PageQuery>\n                    classes={classes!(\"pagination-next\")}\n                    disabled={page==total_pages}\n                    query={Some(PageQuery{page: page + 1})}\n                    {to}\n                >\n                    { \"Next page\" }\n                </Link<Route, PageQuery>>\n            </>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/components/post_card.rs",
    "content": "use yew::prelude::*;\nuse yew_router::components::Link;\n\nuse crate::content::PostMeta;\nuse crate::generator::Generated;\nuse crate::Route;\n\n#[derive(Clone, Debug, PartialEq, Eq, Properties)]\npub struct Props {\n    pub seed: u64,\n}\n\npub struct PostCard {\n    post: PostMeta,\n}\nimpl Component for PostCard {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self {\n            post: PostMeta::generate_from_seed(ctx.props().seed),\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n        self.post = PostMeta::generate_from_seed(ctx.props().seed);\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let Self { post } = self;\n        html! {\n            <div class=\"card\">\n                <div class=\"card-image\">\n                    <figure class=\"image is-2by1\">\n                        <img alt=\"This post's image\" src={post.image_url.clone()} loading=\"lazy\" />\n                    </figure>\n                </div>\n                <div class=\"card-content\">\n                    <Link<Route> classes={classes!(\"title\", \"is-block\")} to={Route::Post { id: post.seed }}>\n                        { &post.title }\n                    </Link<Route>>\n                    <Link<Route> classes={classes!(\"subtitle\", \"is-block\")} to={Route::Author { id: post.author.seed }}>\n                        { &post.author.name }\n                    </Link<Route>>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/components/progress_delay.rs",
    "content": "use gloo::timers::callback::Interval;\nuse instant::Instant;\nuse yew::prelude::*;\n\nconst RESOLUTION: u64 = 500;\nconst MIN_INTERVAL_MS: u64 = 50;\n\npub enum Msg {\n    Tick,\n}\n\n#[derive(Clone, Debug, PartialEq, Properties)]\npub struct Props {\n    pub duration_ms: u64,\n    pub on_complete: Callback<()>,\n    #[prop_or_default]\n    pub on_progress: Callback<f64>,\n}\n\npub struct ProgressDelay {\n    _interval: Interval,\n    start: Instant,\n    value: f64,\n}\nimpl Component for ProgressDelay {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let interval = (ctx.props().duration_ms / RESOLUTION).min(MIN_INTERVAL_MS);\n        let link = ctx.link().clone();\n        let interval = Interval::new(interval as u32, move || link.send_message(Msg::Tick));\n        Self {\n            _interval: interval,\n            start: Instant::now(),\n            value: 0.0,\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Tick => {\n                let duration = ctx.props().duration_ms;\n                let elapsed = self.start.elapsed().as_millis() as u64;\n                self.value = elapsed as f64 / duration as f64;\n\n                if elapsed > duration {\n                    ctx.props().on_complete.emit(());\n                    self.start = Instant::now();\n                } else {\n                    ctx.props().on_progress.emit(self.value);\n                }\n                true\n            }\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let value = self.value;\n        html! {\n            <progress class=\"progress is-primary\" value={value.to_string()} max=1.0>\n                { format!(\"{:.0}%\", 100.0 * value) }\n            </progress>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/content.rs",
    "content": "use crate::generator::{Generated, Generator};\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Author {\n    pub seed: u64,\n    pub name: String,\n    pub keywords: Vec<String>,\n    pub image_url: String,\n}\nimpl Generated for Author {\n    fn generate(gen: &mut Generator) -> Self {\n        let name = gen.human_name();\n        let keywords = gen.keywords();\n        let image_url = gen.face_image_url((150, 150));\n        Self {\n            seed: gen.seed,\n            name,\n            keywords,\n            image_url,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct PostMeta {\n    pub seed: u64,\n    pub title: String,\n    pub author: Author,\n    pub keywords: Vec<String>,\n    pub image_url: String,\n}\nimpl Generated for PostMeta {\n    fn generate(gen: &mut Generator) -> Self {\n        let title = gen.title();\n        let author = Author::generate_from_seed(gen.new_seed());\n        let keywords = gen.keywords();\n        let image_url = gen.image_url((300, 150), &keywords);\n\n        Self {\n            seed: gen.seed,\n            title,\n            author,\n            keywords,\n            image_url,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Post {\n    pub meta: PostMeta,\n    pub content: Vec<PostPart>,\n}\nimpl Generated for Post {\n    fn generate(gen: &mut Generator) -> Self {\n        const PARTS_MIN: usize = 1;\n        const PARTS_MAX: usize = 10;\n\n        let meta = PostMeta::generate(gen);\n\n        let n_parts = gen.range(PARTS_MIN, PARTS_MAX);\n        let content = (0..n_parts).map(|_| PostPart::generate(gen)).collect();\n\n        Self { meta, content }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub enum PostPart {\n    Section(Section),\n    Quote(Quote),\n}\nimpl Generated for PostPart {\n    fn generate(gen: &mut Generator) -> Self {\n        // Because we pass the same (already used) generator down,\n        // the resulting `Section` and `Quote` aren't be reproducible with just the seed.\n        // This doesn't matter here though, because we don't need it.\n        if gen.chance(1, 10) {\n            Self::Quote(Quote::generate(gen))\n        } else {\n            Self::Section(Section::generate(gen))\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Section {\n    pub title: String,\n    pub paragraphs: Vec<String>,\n    pub image_url: String,\n}\nimpl Generated for Section {\n    fn generate(gen: &mut Generator) -> Self {\n        const PARAGRAPHS_MIN: usize = 1;\n        const PARAGRAPHS_MAX: usize = 8;\n\n        let title = gen.title();\n        let n_paragraphs = gen.range(PARAGRAPHS_MIN, PARAGRAPHS_MAX);\n        let paragraphs = (0..n_paragraphs).map(|_| gen.paragraph()).collect();\n        let image_url = gen.image_url((200, 100), &[]);\n\n        Self {\n            title,\n            paragraphs,\n            image_url,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct Quote {\n    pub author: Author,\n    pub content: String,\n}\nimpl Generated for Quote {\n    fn generate(gen: &mut Generator) -> Self {\n        // wouldn't it be funny if the author ended up quoting themselves?\n        let author = Author::generate_from_seed(gen.new_seed());\n        let content = gen.paragraph();\n        Self { author, content }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/generator.rs",
    "content": "use std::sync::LazyLock;\n\nuse lipsum::MarkovChain;\nuse rand::distr::Bernoulli;\nuse rand::rngs::SmallRng;\nuse rand::seq::IteratorRandom;\nuse rand::{Rng, SeedableRng};\n\nconst KEYWORDS: &str = include_str!(\"../data/keywords.txt\");\nconst SYLLABLES: &str = include_str!(\"../data/syllables.txt\");\nconst YEW_CONTENT: &str = include_str!(\"../data/yew.txt\");\n\nstatic YEW_CHAIN: LazyLock<MarkovChain<'static>> = LazyLock::new(|| {\n    let mut chain = MarkovChain::new();\n    chain.learn(YEW_CONTENT);\n    chain\n});\n\npub struct Generator {\n    pub seed: u64,\n    rng: SmallRng,\n}\nimpl Generator {\n    pub fn from_seed(seed: u64) -> Self {\n        let rng = SmallRng::seed_from_u64(seed);\n\n        Self { seed, rng }\n    }\n}\nimpl Generator {\n    pub fn new_seed(&mut self) -> u64 {\n        self.rng.random()\n    }\n\n    /// [low, high)\n    pub fn range(&mut self, low: usize, high: usize) -> usize {\n        self.rng.random_range(low..high)\n    }\n\n    /// `n / d` chance\n    pub fn chance(&mut self, n: u32, d: u32) -> bool {\n        self.rng.sample(Bernoulli::from_ratio(n, d).unwrap())\n    }\n\n    pub fn image_url(&mut self, dimension: (usize, usize), _keywords: &[String]) -> String {\n        let seed: u32 = self.rng.random();\n        let (width, height) = dimension;\n        function_router::imagegen::generate_data_url(width as u32, height as u32, seed)\n    }\n\n    pub fn face_image_url(&mut self, dimension: (usize, usize)) -> String {\n        let seed: u32 = self.rng.random();\n        let (width, height) = dimension;\n        function_router::imagegen::generate_data_url(width as u32, height as u32, seed)\n    }\n\n    pub fn human_name(&mut self) -> String {\n        const SYLLABLES_MIN: usize = 1;\n        const SYLLABLES_MAX: usize = 5;\n\n        let n_syllables = self.rng.random_range(SYLLABLES_MIN..SYLLABLES_MAX);\n        let first_name = SYLLABLES\n            .split_whitespace()\n            .choose_multiple(&mut self.rng, n_syllables)\n            .join(\"\");\n\n        let n_syllables = self.rng.random_range(SYLLABLES_MIN..SYLLABLES_MAX);\n        let last_name = SYLLABLES\n            .split_whitespace()\n            .choose_multiple(&mut self.rng, n_syllables)\n            .join(\"\");\n\n        format!(\"{} {}\", title_case(&first_name), title_case(&last_name))\n    }\n\n    pub fn keywords(&mut self) -> Vec<String> {\n        const KEYWORDS_MIN: usize = 1;\n        const KEYWORDS_MAX: usize = 4;\n\n        let n_keywords = self.rng.random_range(KEYWORDS_MIN..KEYWORDS_MAX);\n        KEYWORDS\n            .split_whitespace()\n            .map(ToOwned::to_owned)\n            .choose_multiple(&mut self.rng, n_keywords)\n    }\n\n    pub fn title(&mut self) -> String {\n        const WORDS_MIN: usize = 3;\n        const WORDS_MAX: usize = 8;\n        const SMALL_WORD_LEN: usize = 3;\n\n        let n_words = self.rng.random_range(WORDS_MIN..WORDS_MAX);\n        let mut title = String::new();\n\n        let words = YEW_CHAIN\n            .iter(&mut self.rng, None)\n            .map(|word: &str| word.trim_matches(|c: char| c.is_ascii_punctuation()))\n            .filter(|word| !word.is_empty())\n            .take(n_words);\n\n        for (i, word) in words.enumerate() {\n            if i > 0 {\n                title.push(' ');\n            }\n\n            // Capitalize the first word and all long words.\n            if i == 0 || word.len() > SMALL_WORD_LEN {\n                title.push_str(&title_case(word));\n            } else {\n                title.push_str(word);\n            }\n        }\n        title\n    }\n\n    pub fn sentence(&mut self) -> String {\n        const WORDS_MIN: usize = 7;\n        const WORDS_MAX: usize = 25;\n\n        let n_words = self.rng.random_range(WORDS_MIN..WORDS_MAX);\n        join_words(YEW_CHAIN.iter(&mut self.rng, None).take(n_words))\n    }\n\n    pub fn paragraph(&mut self) -> String {\n        const SENTENCES_MIN: usize = 3;\n        const SENTENCES_MAX: usize = 20;\n\n        let n_sentences = self.rng.random_range(SENTENCES_MIN..SENTENCES_MAX);\n        let mut paragraph = String::new();\n        for i in 0..n_sentences {\n            if i > 0 {\n                paragraph.push(' ');\n            }\n\n            paragraph.push_str(&self.sentence());\n        }\n        paragraph\n    }\n}\n\nfn join_words<'a>(words: impl Iterator<Item = &'a str>) -> String {\n    let mut result = String::new();\n    for (i, word) in words.enumerate() {\n        if i > 0 {\n            result.push(' ');\n        }\n        if i == 0 {\n            result.push_str(&title_case(word));\n        } else {\n            result.push_str(word);\n        }\n    }\n    if !result.is_empty() && !result.ends_with(|c: char| c.is_ascii_punctuation()) {\n        result.push('.');\n    }\n    result\n}\n\nfn title_case(word: &str) -> String {\n    let idx = match word.chars().next() {\n        Some(c) => c.len_utf8(),\n        None => 0,\n    };\n\n    let mut result = String::with_capacity(word.len());\n    result.push_str(&word[..idx].to_uppercase());\n    result.push_str(&word[idx..]);\n    result\n}\n\npub trait Generated: Sized {\n    fn generate(gen: &mut Generator) -> Self;\n    fn generate_from_seed(seed: u64) -> Self {\n        Self::generate(&mut Generator::from_seed(seed))\n    }\n}\n"
  },
  {
    "path": "examples/router/src/lib.rs",
    "content": "\n"
  },
  {
    "path": "examples/router/src/main.rs",
    "content": "use yew::prelude::*;\nuse yew_router::prelude::*;\n\nmod components;\nmod content;\nmod generator;\nmod pages;\nuse pages::author::Author;\nuse pages::author_list::AuthorList;\nuse pages::home::Home;\nuse pages::page_not_found::PageNotFound;\nuse pages::post::Post;\nuse pages::post_list::PostList;\nuse yew::html::Scope;\n\n#[derive(Routable, PartialEq, Eq, Clone, Debug)]\npub enum Route {\n    #[at(\"/posts/:id\")]\n    Post { id: u64 },\n    #[at(\"/posts\")]\n    Posts,\n    #[at(\"/authors/:id\")]\n    Author { id: u64 },\n    #[at(\"/authors\")]\n    Authors,\n    #[at(\"/\")]\n    Home,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\npub enum Msg {\n    ToggleNavbar,\n}\n\npub struct App {\n    navbar_active: bool,\n}\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            navbar_active: false,\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ToggleNavbar => {\n                self.navbar_active = !self.navbar_active;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <BrowserRouter>\n                { self.view_nav(ctx.link()) }\n\n                <main>\n                    <Switch<Route> render={switch} />\n                </main>\n                <footer class=\"footer\">\n                    <div class=\"content has-text-centered\">\n                        { \"Powered by \" }\n                        <a href=\"https://yew.rs\">{ \"Yew\" }</a>\n                        { \" using \" }\n                        <a href=\"https://bulma.io\">{ \"Bulma\" }</a>\n                    </div>\n                </footer>\n            </BrowserRouter>\n        }\n    }\n}\nimpl App {\n    fn view_nav(&self, link: &Scope<Self>) -> Html {\n        let Self { navbar_active, .. } = *self;\n\n        let active_class = if !navbar_active { \"is-active\" } else { \"\" };\n\n        html! {\n            <nav class=\"navbar is-primary\" role=\"navigation\" aria-label=\"main navigation\">\n                <div class=\"navbar-brand\">\n                    <h1 class=\"navbar-item is-size-3\">{ \"Yew Blog\" }</h1>\n\n                    <button class={classes!(\"navbar-burger\", \"burger\", active_class)}\n                        aria-label=\"menu\" aria-expanded=\"false\"\n                        onclick={link.callback(|_| Msg::ToggleNavbar)}\n                    >\n                        <span aria-hidden=\"true\"></span>\n                        <span aria-hidden=\"true\"></span>\n                        <span aria-hidden=\"true\"></span>\n                    </button>\n                </div>\n                <div class={classes!(\"navbar-menu\", active_class)}>\n                    <div class=\"navbar-start\">\n                        <Link<Route> classes={classes!(\"navbar-item\")} to={Route::Home}>\n                            { \"Home\" }\n                        </Link<Route>>\n                        <Link<Route> classes={classes!(\"navbar-item\")} to={Route::Posts}>\n                            { \"Posts\" }\n                        </Link<Route>>\n\n                        <div class=\"navbar-item has-dropdown is-hoverable\">\n                            <div class=\"navbar-link\">\n                                { \"More\" }\n                            </div>\n                            <div class=\"navbar-dropdown\">\n                                <Link<Route> classes={classes!(\"navbar-item\")} to={Route::Authors}>\n                                    { \"Meet the authors\" }\n                                </Link<Route>>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </nav>\n        }\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Post { id } => {\n            html! { <Post seed={id} /> }\n        }\n        Route::Posts => {\n            html! { <PostList /> }\n        }\n        Route::Author { id } => {\n            html! { <Author seed={id} /> }\n        }\n        Route::Authors => {\n            html! { <AuthorList /> }\n        }\n        Route::Home => {\n            html! { <Home /> }\n        }\n        Route::NotFound => {\n            html! { <PageNotFound /> }\n        }\n    }\n}\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/router/src/pages/author.rs",
    "content": "use yew::prelude::*;\n\nuse crate::content;\nuse crate::generator::Generated;\n\n#[derive(Clone, Debug, Eq, PartialEq, Properties)]\npub struct Props {\n    pub seed: u64,\n}\n\npub struct Author {\n    author: content::Author,\n}\nimpl Component for Author {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self {\n            author: content::Author::generate_from_seed(ctx.props().seed),\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n        self.author = content::Author::generate_from_seed(ctx.props().seed);\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let Self { author } = self;\n\n        html! {\n            <div class=\"section container\">\n                <div class=\"tile is-ancestor is-vertical\">\n                    <div class=\"tile is-parent\">\n                        <article class=\"tile is-child notification is-light\">\n                            <p class=\"title\">{ &author.name }</p>\n                        </article>\n                    </div>\n                    <div class=\"tile\">\n                        <div class=\"tile is-parent is-3\">\n                            <article class=\"tile is-child notification\">\n                                <p class=\"title\">{ \"Interests\" }</p>\n                                <div class=\"tags\">\n                                    { for author.keywords.iter().map(|tag| html! { <span class=\"tag is-info\">{ tag }</span> }) }\n                                </div>\n                            </article>\n                        </div>\n                        <div class=\"tile is-parent\">\n                            <figure class=\"tile is-child image is-square\">\n                                <img alt=\"The author's profile picture.\" src={author.image_url.clone()} />\n                            </figure>\n                        </div>\n                        <div class=\"tile is-parent\">\n                            <article class=\"tile is-child notification is-info\">\n                                <div class=\"content\">\n                                    <p class=\"title\">{ \"About me\" }</p>\n                                    <div class=\"content\">\n                                        { \"This author has chosen not to reveal anything about themselves\" }\n                                    </div>\n                                </div>\n                            </article>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/pages/author_list.rs",
    "content": "use rand::{distr, Rng};\nuse yew::prelude::*;\n\nuse crate::components::author_card::AuthorCard;\nuse crate::components::progress_delay::ProgressDelay;\n\n/// Amount of milliseconds to wait before showing the next set of authors.\nconst CAROUSEL_DELAY_MS: u64 = 15000;\n\npub enum Msg {\n    NextAuthors,\n}\n\npub struct AuthorList {\n    seeds: Vec<u64>,\n}\nimpl Component for AuthorList {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            seeds: random_author_seeds(),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::NextAuthors => {\n                self.seeds = random_author_seeds();\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let authors = self.seeds.iter().map(|&seed| {\n            html! {\n                <div class=\"tile is-parent\">\n                    <div class=\"tile is-child\">\n                        <AuthorCard {seed} />\n                    </div>\n                </div>\n            }\n        });\n\n        html! {\n            <div class=\"container\">\n                <section class=\"hero\">\n                    <div class=\"hero-body\">\n                        <div class=\"container\">\n                            <h1 class=\"title\">{ \"Authors\" }</h1>\n                            <h2 class=\"subtitle\">\n                                { \"Meet the definitely real people behind your favourite Yew content\" }\n                            </h2>\n                        </div>\n                    </div>\n                </section>\n                <p class=\"section py-0\">\n                    { \"It wouldn't be fair \" }\n                    <i>{ \"(or possible :P)\" }</i>\n                    {\" to list each and every author in alphabetical order.\"}\n                    <br />\n                    { \"So instead we chose to put more focus on the individuals by introducing you to two people at a time\" }\n                </p>\n                <div class=\"section\">\n                    <div class=\"tile is-ancestor\">\n                        { for authors }\n                    </div>\n                    <ProgressDelay duration_ms={CAROUSEL_DELAY_MS} on_complete={ctx.link().callback(|_| Msg::NextAuthors)} />\n                </div>\n            </div>\n        }\n    }\n}\n\nfn random_author_seeds() -> Vec<u64> {\n    rand::rng()\n        .sample_iter(distr::StandardUniform)\n        .take(2)\n        .collect()\n}\n"
  },
  {
    "path": "examples/router/src/pages/home.rs",
    "content": "use yew::prelude::*;\n\npub struct Home;\nimpl Component for Home {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"tile is-ancestor is-vertical\">\n                <div class=\"tile is-child hero\">\n                    <div class=\"hero-body container pb-0\">\n                        <h1 class=\"title is-1\">{ \"Welcome...\" }</h1>\n                        <h2 class=\"subtitle\">{ \"...to the best yew content\" }</h2>\n                    </div>\n                </div>\n\n                <div class=\"tile is-child\">\n                    <figure class=\"image is-3by1\">\n                        <img alt=\"A procedurally generated decorative image.\" src={function_router::imagegen::generate_data_url(600, 200, 42)} />\n                    </figure>\n                </div>\n\n                <div class=\"tile is-parent container\">\n                    { self.view_info_tiles() }\n                </div>\n            </div>\n        }\n    }\n}\nimpl Home {\n    fn view_info_tiles(&self) -> Html {\n        html! {\n            <>\n                <div class=\"tile is-parent\">\n                    <div class=\"tile is-child box\">\n                        <p class=\"title\">{ \"What are yews?\" }</p>\n                        <p class=\"subtitle\">{ \"Everything you need to know!\" }</p>\n\n                        <div class=\"content\">\n                            {r#\"\n                            A yew is a small to medium-sized evergreen tree, growing 10 to 20 metres tall, with a trunk up to 2 metres in diameter.\n                            The bark is thin, scaly brown, coming off in small flakes aligned with the stem.\n                            The leaves are flat, dark green, 1 to 4 centimetres long and 2 to 3 millimetres broad, arranged spirally on the stem,\n                            but with the leaf bases twisted to align the leaves in two flat rows either side of the stem,\n                            except on erect leading shoots where the spiral arrangement is more obvious.\n                            The leaves are poisonous.\n                            \"#}\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"tile is-parent\">\n                    <div class=\"tile is-child box\">\n                        <p class=\"title\">{ \"Who are we?\" }</p>\n\n                        <div class=\"content\">\n                            { \"We're a small team of just 2\" }\n                            <sup>{ 64 }</sup>\n                            { \" members working tirelessly to bring you the low-effort yew content we all desperately crave.\" }\n                            <br />\n                            {r#\"\n                                We put a ton of effort into fact-checking our posts.\n                                Some say they read like a Wikipedia article - what a compliment!\n                            \"#}\n                        </div>\n                    </div>\n                </div>\n            </>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/pages/mod.rs",
    "content": "pub mod author;\npub mod author_list;\npub mod home;\npub mod page_not_found;\npub mod post;\npub mod post_list;\n"
  },
  {
    "path": "examples/router/src/pages/page_not_found.rs",
    "content": "use yew::prelude::*;\n\npub struct PageNotFound;\n\nimpl Component for PageNotFound {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            <section class=\"hero is-danger is-bold is-large\">\n                <div class=\"hero-body\">\n                    <div class=\"container\">\n                        <h1 class=\"title\">\n                            { \"Page not found\" }\n                        </h1>\n                        <h2 class=\"subtitle\">\n                            { \"Page page does not seem to exist\" }\n                        </h2>\n                    </div>\n                </div>\n            </section>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/router/src/pages/post.rs",
    "content": "use content::PostPart;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::generator::Generated;\nuse crate::{content, Route};\n\n#[derive(Clone, Debug, Eq, PartialEq, Properties)]\npub struct Props {\n    pub seed: u64,\n}\n\npub struct Post {\n    post: content::Post,\n}\nimpl Component for Post {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self {\n            post: content::Post::generate_from_seed(ctx.props().seed),\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n        self.post = content::Post::generate_from_seed(ctx.props().seed);\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        let Self { post } = self;\n\n        let keywords = post\n            .meta\n            .keywords\n            .iter()\n            .map(|keyword| html! { <span class=\"tag is-info\">{ keyword }</span> });\n\n        html! {\n            <>\n                <section class=\"hero is-medium is-light has-background\">\n                    <img alt=\"The hero's background\" class=\"hero-background is-transparent\" src={post.meta.image_url.clone()} />\n                    <div class=\"hero-body\">\n                        <div class=\"container\">\n                            <h1 class=\"title\">\n                                { &post.meta.title }\n                            </h1>\n                            <h2 class=\"subtitle\">\n                                { \"by \" }\n                                <Link<Route> classes={classes!(\"has-text-weight-semibold\")} to={Route::Author { id: post.meta.author.seed }}>\n                                    { &post.meta.author.name }\n                                </Link<Route>>\n                            </h2>\n                            <div class=\"tags\">\n                                { for keywords }\n                            </div>\n                        </div>\n                    </div>\n                </section>\n                <div class=\"section container\">\n                    { self.view_content() }\n                </div>\n            </>\n        }\n    }\n}\nimpl Post {\n    fn render_quote(&self, quote: &content::Quote) -> Html {\n        html! {\n            <article class=\"media block box my-6\">\n                <figure class=\"media-left\">\n                    <p class=\"image is-64x64\">\n                        <img alt=\"The author's profile\" src={quote.author.image_url.clone()} loading=\"lazy\" />\n                    </p>\n                </figure>\n                <div class=\"media-content\">\n                    <div class=\"content\">\n                        <Link<Route> classes={classes!(\"is-size-5\")} to={Route::Author { id: quote.author.seed }}>\n                            <strong>{ &quote.author.name }</strong>\n                        </Link<Route>>\n                        <p class=\"is-family-secondary\">\n                            { &quote.content }\n                        </p>\n                    </div>\n                </div>\n            </article>\n        }\n    }\n\n    fn render_section_hero(&self, section: &content::Section) -> Html {\n        html! {\n            <section class=\"hero is-dark has-background mt-6 mb-3\">\n                <img alt=\"This section's image\" class=\"hero-background is-transparent\" src={section.image_url.clone()} loading=\"lazy\" />\n                <div class=\"hero-body\">\n                    <div class=\"container\">\n                        <h2 class=\"subtitle\">{ &section.title }</h2>\n                    </div>\n                </div>\n            </section>\n        }\n    }\n\n    fn render_section(&self, section: &content::Section, show_hero: bool) -> Html {\n        let hero = if show_hero {\n            self.render_section_hero(section)\n        } else {\n            html! {}\n        };\n        let paragraphs = section.paragraphs.iter().map(|paragraph| {\n            html! {\n                <p>{ paragraph }</p>\n            }\n        });\n        html! {\n            <section>\n                { hero }\n                <div>{ for paragraphs }</div>\n            </section>\n        }\n    }\n\n    fn view_content(&self) -> Html {\n        // don't show hero for the first section\n        let mut show_hero = false;\n\n        let parts = self.post.content.iter().map(|part| match part {\n            PostPart::Section(section) => {\n                let html = self.render_section(section, show_hero);\n                // show hero between sections\n                show_hero = true;\n                html\n            }\n            PostPart::Quote(quote) => {\n                // don't show hero after a quote\n                show_hero = false;\n                self.render_quote(quote)\n            }\n        });\n        html! {{for parts}}\n    }\n}\n"
  },
  {
    "path": "examples/router/src/pages/post_list.rs",
    "content": "use yew::prelude::*;\nuse yew_router::prelude::*;\n\nuse crate::components::pagination::{PageQuery, Pagination};\nuse crate::components::post_card::PostCard;\nuse crate::Route;\n\nconst ITEMS_PER_PAGE: u64 = 10;\nconst TOTAL_PAGES: u64 = u64::MAX / ITEMS_PER_PAGE;\n\npub enum Msg {\n    PageUpdated,\n}\n\npub struct PostList {\n    page: u64,\n    _listener: LocationHandle,\n}\n\nfn current_page(ctx: &Context<PostList>) -> u64 {\n    let location = ctx.link().location().unwrap();\n\n    location.query::<PageQuery>().map(|it| it.page).unwrap_or(1)\n}\n\nimpl Component for PostList {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let link = ctx.link().clone();\n        let listener = ctx\n            .link()\n            .add_location_listener(link.callback(move |_| Msg::PageUpdated))\n            .unwrap();\n\n        Self {\n            page: current_page(ctx),\n            _listener: listener,\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::PageUpdated => self.page = current_page(ctx),\n        }\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let page = self.page;\n\n        html! {\n            <div class=\"section container\">\n                <h1 class=\"title\">{ \"Posts\" }</h1>\n                <h2 class=\"subtitle\">{ \"All of our quality writing in one place\" }</h2>\n                { self.view_posts(ctx) }\n                <Pagination\n                    {page}\n                    total_pages={TOTAL_PAGES}\n                    route_to_page={Route::Posts}\n                />\n            </div>\n        }\n    }\n}\nimpl PostList {\n    fn view_posts(&self, _ctx: &Context<Self>) -> Html {\n        let start_seed = (self.page - 1) * ITEMS_PER_PAGE;\n        let mut cards = (0..ITEMS_PER_PAGE).map(|seed_offset| {\n            html! {\n                <li class=\"list-item mb-5\">\n                    <PostCard seed={start_seed + seed_offset} />\n                </li>\n            }\n        });\n        html! {\n            <div class=\"columns\">\n                <div class=\"column\">\n                    <ul class=\"list\">\n                        { for cards.by_ref().take(ITEMS_PER_PAGE as usize / 2) }\n                    </ul>\n                </div>\n                <div class=\"column\">\n                    <ul class=\"list\">\n                        { for cards }\n                    </ul>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/simple_ssr/Cargo.toml",
    "content": "[package]\nname = \"simple_ssr\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n[[bin]]\nname = \"simple_ssr_hydrate\"\nrequired-features = [\"hydration\"]\n\n[[bin]]\nname = \"simple_ssr_server\"\nrequired-features = [\"ssr\"]\n\n[dependencies]\nyew = { path = \"../../packages/yew\" }\nreqwest = { workspace = true, features = [\"json\"] }\nserde = { workspace = true, features = [\"derive\"] }\nuuid = { version = \"1.20.0\", features = [\"serde\"] }\nfutures.workspace = true\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen-futures.workspace = true\nwasm-logger.workspace = true\nlog.workspace = true\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\ntokio = { workspace = true, features = [\"macros\", \"rt-multi-thread\", \"fs\"] }\nwarp = { git = \"https://github.com/seanmonstar/warp.git\", rev = \"de1ccd8\", features = [\"server\"] }\nclap = { workspace = true }\n\n[target.'cfg(target_arch = \"wasm32\")'.dev-dependencies]\nwasm-bindgen-test.workspace = true\nssr-e2e-harness = { path = \"../../tools/ssr-e2e-harness\" }\n\n[dev-dependencies]\nyew = { path = \"../../packages/yew\", features = [\"hydration\"] }\n\n[features]\nhydration = [\"yew/hydration\"]\nssr = [\"yew/ssr\"]\n"
  },
  {
    "path": "examples/simple_ssr/README.md",
    "content": "# Server-side Rendering Example\n\nThis example demonstrates server-side rendering.\n\n# Running\n\n1. Build hydration bundle\n\n`trunk build index.html`\n\n2. Run the server\n\n`cargo run --features=ssr --bin simple_ssr_server -- --dir dist`"
  },
  {
    "path": "examples/simple_ssr/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Yew SSR Example</title>\n\n  <link data-trunk rel=\"rust\" data-bin=\"simple_ssr_hydrate\" data-cargo-features=\"hydration\" />\n</head>\n\n<body></body>\n\n</html>"
  },
  {
    "path": "examples/simple_ssr/src/bin/simple_ssr_hydrate.rs",
    "content": "use simple_ssr::App;\n\nfn main() {\n    #[cfg(target_arch = \"wasm32\")]\n    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));\n    yew::Renderer::<App>::new().hydrate();\n}\n"
  },
  {
    "path": "examples/simple_ssr/src/bin/simple_ssr_server.rs",
    "content": "use std::convert::Infallible;\nuse std::path::PathBuf;\n\nuse clap::Parser;\nuse futures::stream::{self, Stream, StreamExt};\nuse simple_ssr::App;\nuse warp::Filter;\n\n/// A basic example\n#[derive(Parser, Debug)]\nstruct Opt {\n    /// the \"dist\" created by trunk directory to be served for hydration.\n    #[structopt(short, long)]\n    dir: PathBuf,\n}\n\nasync fn render(\n    index_html_before: String,\n    index_html_after: String,\n) -> impl Stream<Item = Result<String, Infallible>> {\n    let renderer = yew::ServerRenderer::<App>::new();\n\n    stream::once(async move { Ok(index_html_before) })\n        .chain(renderer.render_stream().map(Ok))\n        .chain(stream::once(async move { Ok(index_html_after) }))\n}\n\n#[tokio::main]\nasync fn main() {\n    let opts = Opt::parse();\n\n    let index_html_s = tokio::fs::read_to_string(opts.dir.join(\"index.html\"))\n        .await\n        .expect(\"failed to read index.html\");\n\n    let (index_html_before, index_html_after) = index_html_s.split_once(\"<body>\").unwrap();\n    let mut index_html_before = index_html_before.to_owned();\n    index_html_before.push_str(\"<body>\");\n    let index_html_after = index_html_after.to_owned();\n\n    let html = warp::path::end().then(move || {\n        let index_html_before = index_html_before.clone();\n        let index_html_after = index_html_after.clone();\n\n        async move {\n            let body = render(index_html_before, index_html_after).await;\n            warp::reply::with_header(\n                warp::reply::stream(body),\n                \"content-type\",\n                \"text/html; charset=utf-8\",\n            )\n        }\n    });\n\n    let cors = warp::cors()\n        .allow_any_origin()\n        .allow_methods(vec![\"GET\"])\n        .allow_headers(vec![\"content-type\"]);\n\n    let routes = html.or(warp::fs::dir(opts.dir)).with(cors);\n\n    println!(\"You can view the website at: http://localhost:8080/\");\n    warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;\n}\n"
  },
  {
    "path": "examples/simple_ssr/src/lib.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse uuid::Uuid;\nuse yew::prelude::*;\n\n#[derive(Serialize, Deserialize)]\nstruct UuidResponse {\n    uuid: Uuid,\n}\n\n#[cfg(feature = \"ssr\")]\nasync fn fetch_uuid() -> Uuid {\n    // reqwest works for both non-wasm and wasm targets.\n    let resp = reqwest::get(\"https://httpbin.org/uuid\").await.unwrap();\n    let uuid_resp = resp.json::<UuidResponse>().await.unwrap();\n\n    uuid_resp.uuid\n}\n\n#[function_component]\nfn Content() -> HtmlResult {\n    let uuid = use_prepared_state!((), async move |_| -> Uuid { fetch_uuid().await })?.unwrap();\n\n    Ok(html! {\n        <div>{\"Random UUID: \"}{uuid}</div>\n    })\n}\n\n#[function_component]\npub fn App() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n"
  },
  {
    "path": "examples/simple_ssr/tests/e2e.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nuse simple_ssr::App;\nuse ssr_e2e_harness::{output_element, setup_ssr_page, wait_for};\nuse wasm_bindgen_test::*;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\nconst SERVER_BASE: &str = \"http://127.0.0.1:8080\";\n\n#[wasm_bindgen_test]\nasync fn hydration_succeeds() {\n    setup_ssr_page(SERVER_BASE, \"/\").await;\n    yew::Renderer::<App>::with_root(output_element()).hydrate();\n\n    wait_for(\n        || {\n            let html = output_element().inner_html();\n            html.contains(\"Random UUID:\")\n        },\n        5000,\n        \"SSR content with UUID\",\n    )\n    .await;\n\n    let html = output_element().inner_html();\n    assert!(\n        html.contains(\"Random UUID:\"),\n        \"hydrated content should contain the UUID text\"\n    );\n}\n"
  },
  {
    "path": "examples/ssr_router/Cargo.toml",
    "content": "[package]\nname = \"ssr_router\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[[bin]]\nname = \"ssr_router_hydrate\"\nrequired-features = [\"hydration\"]\n\n[[bin]]\nname = \"ssr_router_server\"\nrequired-features = [\"ssr\"]\n\n[dependencies]\nyew = { path = \"../../packages/yew\" }\nfunction_router = { path = \"../function_router\" }\nlog = \"0.4\"\nfutures = { workspace = true, features = [\"std\"] }\nhyper-util = \"0.1.20\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen-futures.workspace = true\nwasm-logger.workspace = true\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\nyew-router = { path = \"../../packages/yew-router\" }\ntokio = { workspace = true, features = [\"macros\", \"rt-multi-thread\", \"net\", \"fs\"] }\naxum = \"0.8\"\ntower = { version = \"0.5\", features = [\"make\"] }\ntower-http = { version = \"0.6\", features = [\"fs\", \"cors\"] }\nenv_logger = \"0.11\"\nclap = { workspace = true }\nhyper = { version = \"1.4\", features = [\"server\", \"http1\"] }\n\n[target.'cfg(unix)'.dependencies]\njemallocator = \"0.5\"\n\n[target.'cfg(target_arch = \"wasm32\")'.dev-dependencies]\nwasm-bindgen-test.workspace = true\ngloo = { workspace = true }\nssr-e2e-harness = { path = \"../../tools/ssr-e2e-harness\" }\n\n[dev-dependencies]\nyew = { path = \"../../packages/yew\", features = [\"hydration\"] }\n\n[features]\nssr = [\"yew/ssr\"]\nhydration = [\"yew/hydration\"]\n"
  },
  {
    "path": "examples/ssr_router/README.md",
    "content": "# SSR Router Example\n\nThis example is the same as the function router example, but with\nserver-side rendering and hydration support. It reuses the same codebase\nof the function router example.\n\n# How to run this example\n\n1. Build Hydration Bundle\n\n`trunk build`\n\n2. Run the server\n\n`cargo run --features=ssr --bin ssr_router_server -- --dir dist`\n"
  },
  {
    "path": "examples/ssr_router/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <link data-trunk rel=\"rust\" data-bin=\"ssr_router_hydrate\" data-cargo-features=\"hydration\" />\n\n    <title>Yew SSR Router</title>\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css\"\n    />\n    <link data-trunk rel=\"sass\" href=\"../function_router/index.scss\" />\n  </head>\n\t<body>\n\t</body>\n</html>\n"
  },
  {
    "path": "examples/ssr_router/src/bin/ssr_router_hydrate.rs",
    "content": "use function_router::App;\n\nfn main() {\n    #[cfg(target_arch = \"wasm32\")]\n    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));\n    yew::Renderer::<App>::new().hydrate();\n}\n"
  },
  {
    "path": "examples/ssr_router/src/bin/ssr_router_server.rs",
    "content": "use std::collections::HashMap;\nuse std::convert::Infallible;\nuse std::future::Future;\nuse std::net::SocketAddr;\nuse std::path::PathBuf;\n\nuse axum::body::Body;\nuse axum::extract::{Query, Request, State};\nuse axum::handler::HandlerWithoutStateExt;\nuse axum::http::Uri;\nuse axum::response::IntoResponse;\nuse axum::routing::get;\nuse axum::Router;\nuse clap::Parser;\nuse function_router::{route_meta, Route, ServerApp, ServerAppProps};\nuse futures::stream::{self, StreamExt};\nuse hyper::body::Incoming;\nuse hyper_util::rt::TokioIo;\nuse hyper_util::server;\nuse tokio::net::TcpListener;\nuse tower::Service;\nuse tower_http::cors::CorsLayer;\nuse tower_http::services::ServeDir;\nuse yew::platform::Runtime;\nuse yew_router::prelude::Routable;\n\n// We use jemalloc as it produces better performance.\n#[cfg(unix)]\n#[global_allocator]\nstatic GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;\n\n/// A basic example\n#[derive(Parser, Debug)]\nstruct Opt {\n    /// the \"dist\" created by trunk directory to be served for hydration.\n    #[clap(short, long)]\n    dir: PathBuf,\n}\n\nfn head_tags_for(path: &str) -> String {\n    let route = Route::recognize(path).unwrap_or(Route::NotFound);\n    let (title, description) = route_meta(&route);\n    format!(\n        \"<title>{title} | Yew SSR Router</title><meta name=\\\"description\\\" \\\n         content=\\\"{description}\\\" />\"\n    )\n}\n\nasync fn render(\n    url: Uri,\n    Query(queries): Query<HashMap<String, String>>,\n    State((index_html_before, index_html_after)): State<(String, String)>,\n) -> impl IntoResponse {\n    let path = url.path().to_owned();\n\n    // Inject route-specific <head> tags before </head>, outside of Yew rendering.\n    let before = index_html_before.replace(\"</head>\", &format!(\"{}</head>\", head_tags_for(&path)));\n\n    let renderer = yew::ServerRenderer::<ServerApp>::with_props(move || ServerAppProps {\n        url: path.into(),\n        queries,\n    });\n\n    Body::from_stream(\n        stream::once(async move { before })\n            .chain(renderer.render_stream())\n            .chain(stream::once(async move { index_html_after }))\n            .map(Result::<_, Infallible>::Ok),\n    )\n}\n\n// An executor to process requests on the Yew runtime.\n//\n// By spawning requests on the Yew runtime,\n// it processes request on the same thread as the rendering task.\n//\n// This increases performance in some environments (e.g.: in VM).\n#[derive(Clone, Default)]\nstruct Executor {\n    inner: Runtime,\n}\n\nimpl<F> hyper::rt::Executor<F> for Executor\nwhere\n    F: Future + Send + 'static,\n{\n    fn execute(&self, fut: F) {\n        self.inner.spawn_pinned(move || async move {\n            fut.await;\n        });\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    let exec = Executor::default();\n\n    env_logger::init();\n\n    let opts = Opt::parse();\n\n    let index_html_s = tokio::fs::read_to_string(opts.dir.join(\"index.html\"))\n        .await\n        .expect(\"failed to read index.html\");\n\n    let (index_html_before, index_html_after) = index_html_s.split_once(\"<body>\").unwrap();\n    let mut index_html_before = index_html_before.to_owned();\n    index_html_before.push_str(\"<body>\");\n\n    let index_html_after = index_html_after.to_owned();\n\n    let app = Router::new()\n        .fallback_service(\n            ServeDir::new(opts.dir)\n                .append_index_html_on_directories(false)\n                .fallback(\n                    get(render)\n                        .with_state((index_html_before.clone(), index_html_after.clone()))\n                        .into_service(),\n                ),\n        )\n        .layer(CorsLayer::permissive());\n\n    let addr: SocketAddr = ([0, 0, 0, 0], 8080).into();\n\n    println!(\"You can view the website at: http://localhost:8080/\");\n\n    let listener = TcpListener::bind(addr).await?;\n\n    // Continuously accept new connections.\n    loop {\n        // In this example we discard the remote address. See `fn serve_with_connect_info` for how\n        // to expose that.\n        let (socket, _remote_addr) = listener.accept().await.unwrap();\n\n        // We don't need to call `poll_ready` because `Router` is always ready.\n        let tower_service = app.clone();\n\n        let exec = exec.clone();\n        // Spawn a task to handle the connection. That way we can handle multiple connections\n        // concurrently.\n        tokio::spawn(async move {\n            // Hyper has its own `AsyncRead` and `AsyncWrite` traits and doesn't use tokio.\n            // `TokioIo` converts between them.\n            let socket = TokioIo::new(socket);\n\n            // Hyper also has its own `Service` trait and doesn't use tower. We can use\n            // `hyper::service::service_fn` to create a hyper `Service` that calls our app through\n            // `tower::Service::call`.\n            let hyper_service = hyper::service::service_fn(move |request: Request<Incoming>| {\n                // We have to clone `tower_service` because hyper's `Service` uses `&self` whereas\n                // tower's `Service` requires `&mut self`.\n                //\n                // We don't need to call `poll_ready` since `Router` is always ready.\n                tower_service.clone().call(request)\n            });\n\n            // `server::conn::auto::Builder` supports both http1 and http2.\n            //\n            // `TokioExecutor` tells hyper to use `tokio::spawn` to spawn tasks.\n            if let Err(err) = server::conn::auto::Builder::new(exec)\n                // `serve_connection_with_upgrades` is required for websockets. If you don't need\n                // that you can use `serve_connection` instead.\n                .serve_connection_with_upgrades(socket, hyper_service)\n                .await\n            {\n                eprintln!(\"failed to serve connection: {err:#}\");\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/ssr_router/src/lib.rs",
    "content": "\n"
  },
  {
    "path": "examples/ssr_router/tests/e2e.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nuse std::time::Duration;\n\nuse function_router::App;\nuse gloo::utils::document;\nuse ssr_e2e_harness::{output_element, setup_ssr_page, wait_for};\nuse wasm_bindgen_test::*;\nuse yew::platform::time::sleep;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\nconst SERVER_BASE: &str = \"http://127.0.0.1:8080\";\n\nfn get_title_text() -> Option<String> {\n    document()\n        .query_selector(\"h1.title\")\n        .ok()\n        .flatten()\n        .map(|el| el.text_content().unwrap_or_default())\n}\n\n#[wasm_bindgen_test]\nasync fn hydrate_post_page() {\n    setup_ssr_page(SERVER_BASE, \"/posts/0\").await;\n    yew::Renderer::<App>::with_root(output_element()).hydrate();\n\n    wait_for(\n        || {\n            let html = output_element().inner_html();\n            html.contains(\"<h1 class=\\\"title\\\">\") && !html.contains(\"Loading post...\")\n        },\n        5000,\n        \"post page content\",\n    )\n    .await;\n\n    let title = get_title_text().expect(\"h1.title should be present on the post page\");\n    assert!(!title.is_empty(), \"post title should not be empty\");\n}\n\n#[wasm_bindgen_test]\nasync fn hydrate_posts_list() {\n    setup_ssr_page(SERVER_BASE, \"/posts\").await;\n    yew::Renderer::<App>::with_root(output_element()).hydrate();\n\n    wait_for(\n        || {\n            document()\n                .query_selector(\"a.title.is-block\")\n                .ok()\n                .flatten()\n                .is_some()\n        },\n        10000,\n        \"post links to appear on /posts\",\n    )\n    .await;\n}\n\n#[wasm_bindgen_test]\nasync fn hydrate_home() {\n    setup_ssr_page(SERVER_BASE, \"/\").await;\n    yew::Renderer::<App>::with_root(output_element()).hydrate();\n\n    sleep(Duration::from_secs(2)).await;\n    let html = output_element().inner_html();\n    assert!(\n        html.contains(\"Welcome\"),\n        \"home page should have content after hydration\"\n    );\n}\n"
  },
  {
    "path": "examples/suspense/Cargo.toml",
    "content": "[package]\nname = \"suspense\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo = { workspace = true, features = [\"futures\"] }\nwasm-bindgen-futures.workspace = true\nwasm-bindgen.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"HtmlTextAreaElement\",\n]\n"
  },
  {
    "path": "examples/suspense/README.md",
    "content": "# Suspense Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fsuspense)](https://examples.yew.rs/suspense)\n\nThis is an example that demonstrates `<Suspense />` support.\n\n## Concepts\n\nThis example shows how `<Suspense />` works in Yew and how you can\ncreate hooks that utilises suspense.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/suspense/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/suspense/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew Suspense Demo</title>\n\n    <link data-trunk rel=\"sass\" href=\"index.scss\" />\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/suspense/index.scss",
    "content": "html, body {\n  font-family: sans-serif;\n\n  margin: 0;\n  padding: 0;\n\n  background-color: rgb(237, 244, 255);\n}\n\n.layout {\n  height: 100vh;\n  width: 100%;\n  display: grid;\n  justify-items: center;\n  align-items: center;\n  grid-template-columns: 1fr 1fr;\n}\n\n.content {\n  height: 600px;\n  width: 600px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n\n  border-radius: 4px;\n  box-shadow: 0 0 5px 0  black;\n\n  background: white;\n}\n\n.content-area {\n  width: 350px;\n  height: 500px;\n\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\ntextarea {\n  width: 300px;\n  height: 300px;\n  font-size: 15px;\n}\n\n.action-area {\n  padding-top: 40px;\n}\n\nbutton {\n  color: white;\n  height: 50px;\n  width: 300px;\n  font-size: 20px;\n  background-color: rgb(88, 164, 255);\n  border-radius: 5px;\n  border: none;\n}\n\n.hint {\n  padding-top: 20px;\n\n  font-size: 12px;\n\n  text-align: center;\n\n  color: rgb(100, 100, 100);\n}\n\nh2 {\n  text-align: center;\n}\n"
  },
  {
    "path": "examples/suspense/src/main.rs",
    "content": "use web_sys::HtmlTextAreaElement;\nuse yew::prelude::*;\n\nmod struct_consumer;\nmod use_sleep;\n\npub use use_sleep::use_sleep;\n\n#[derive(Debug, PartialEq, Properties)]\nstruct PleaseWaitProps {\n    from: &'static str,\n}\n\n#[function_component(PleaseWait)]\nfn please_wait(props: &PleaseWaitProps) -> Html {\n    html! {<div class=\"content-area\">{\"Please wait 5 Seconds for \"}{props.from}{\" component to load...\"}</div>}\n}\n\n#[function_component(AppContent)]\nfn app_content() -> HtmlResult {\n    let resleep = use_sleep()?;\n\n    let value = use_state(|| \"I am writing a long story...\".to_string());\n\n    let on_text_input = {\n        let value = value.clone();\n\n        Callback::from(move |e: InputEvent| {\n            let input: HtmlTextAreaElement = e.target_unchecked_into::<HtmlTextAreaElement>();\n\n            value.set(input.value());\n        })\n    };\n\n    let on_take_a_break = Callback::from(move |_| resleep());\n\n    Ok(html! {\n        <div class=\"content-area\">\n            <textarea value={value.to_string()} oninput={on_text_input} />\n            <div class=\"action-area\">\n                <button onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                <div class=\"hint\">{\"You can take a break at anytime\"}<br />{\"and your work will be preserved.\"}</div>\n            </div>\n        </div>\n    })\n}\n\n#[function_component(App)]\nfn app() -> Html {\n    let fallback_fn = html! {<PleaseWait from=\"function\" />};\n    let fallback_struct = html! {<PleaseWait from=\"struct\" />};\n\n    html! {\n        <div class=\"layout\">\n            <div class=\"content\">\n                <h2>{\"  Yew Suspense Demo -- function component consumer\"}</h2>\n                    <Suspense fallback={fallback_fn}>\n                        <AppContent  />\n                    </Suspense>\n            </div>\n            <div class=\"content\">\n                <h2>{\"Yew Suspense Demo -- struct component consumer\"}</h2>\n                <Suspense fallback={fallback_struct}>\n                        <struct_consumer::AppContent />\n                </Suspense>\n            </div>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/suspense/src/struct_consumer.rs",
    "content": "use web_sys::HtmlTextAreaElement;\nuse yew::prelude::*;\n\nuse crate::use_sleep;\n\n#[function_component]\npub fn WithSleep<Comp>() -> HtmlResult\nwhere\n    Comp: BaseComponent<Properties = AppContentProps>,\n{\n    let sleep = use_sleep()?;\n    let sleep = Callback::from(move |_| sleep());\n    Ok(yew::virtual_dom::VChild::<Comp>::new(AppContentProps { resleep: sleep }, None).into())\n}\n\n#[derive(Debug, PartialEq, Properties)]\npub struct AppContentProps {\n    pub resleep: Callback<()>,\n}\n\npub type AppContent = WithSleep<BaseAppContent>;\n\npub enum Msg {\n    ValueUpdate(String),\n    TakeABreak,\n}\n\npub struct BaseAppContent {\n    value: String,\n}\n\nimpl Component for BaseAppContent {\n    type Message = Msg;\n    type Properties = AppContentProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            value: \"I am writing a long story...\".to_string(),\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::ValueUpdate(v) => {\n                self.value = v;\n            }\n            Msg::TakeABreak => {\n                ctx.props().resleep.emit(());\n            }\n        };\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let oninput = ctx.link().callback(|e: InputEvent| {\n            let input: HtmlTextAreaElement = e.target_unchecked_into::<HtmlTextAreaElement>();\n            Msg::ValueUpdate(input.value())\n        });\n        let on_take_a_break = ctx.link().callback(|_| Msg::TakeABreak);\n        html! {\n            <div class=\"content-area\">\n                <textarea value={self.value.clone()} {oninput} />\n                <div class=\"action-area\">\n                    <button onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                    <div class=\"hint\">{\"You can take a break at anytime\"}<br />{\"and your work will be preserved.\"}</div>\n                </div>\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "examples/suspense/src/use_sleep.rs",
    "content": "use std::rc::Rc;\nuse std::time::Duration;\n\nuse gloo::timers::future::sleep;\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(PartialEq)]\npub struct SleepState {\n    s: Suspension,\n}\n\nimpl SleepState {\n    fn new() -> Self {\n        let s = Suspension::from_future(async {\n            sleep(Duration::from_secs(5)).await;\n        });\n\n        Self { s }\n    }\n}\n\nimpl Reducible for SleepState {\n    type Action = ();\n\n    fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n        Self::new().into()\n    }\n}\n\n#[hook]\npub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n    let sleep_state = use_reducer(SleepState::new);\n\n    if sleep_state.s.resumed() {\n        Ok(Rc::new(move || sleep_state.dispatch(())))\n    } else {\n        Err(sleep_state.s.clone())\n    }\n}\n"
  },
  {
    "path": "examples/timer/Cargo.toml",
    "content": "[package]\nname = \"timer\"\nversion = \"0.1.0\"\nauthors = [\"Denis Kolodin <deniskolodin@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\njs-sys.workspace = true\ngloo.workspace = true\nwasm-bindgen.workspace = true\n"
  },
  {
    "path": "examples/timer/README.md",
    "content": "# Timer Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ftimer)](https://examples.yew.rs/timer)\n\nThis is a technical demonstration for how to use timeouts and intervals.\n\n## Concepts\n\nThe example mainly demonstrates the use of [`gloo_timer`](https://docs.rs/gloo-timers/ ) and \n[`gloo_console_timer`](https://docs.rs/gloo-console/latest/gloo_console/struct.Timer.html) but also makes use of some \nmore advanced web console features.\n\n## Improvements\n\n- Apply the concept to something more fun than just a dry technical demonstration\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/timer/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/timer/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Yew • Timer</title>\n  <link data-trunk rel=\"scss\" href=\"index.scss\"/>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@900&display=swap\" rel=\"stylesheet\">\n  <link data-trunk rel=\"rust\" />\n</head>\n\n<body></body>\n\n</html>\n"
  },
  {
    "path": "examples/timer/index.scss",
    "content": "$font-stack:    Roboto, sans-serif;\n$primary-color: #008f53;\n\nbody {\n    font: 100% $font-stack;\n    color: white;\n    background-color: $primary-color;\n}\n\n#buttons {\n    text-align: right;\n}\n\n#wrapper {\n    overflow: hidden;\n    width: 100%;\n}\n\n#time {\n    text-align: center;\n    font-size: 17vh;\n    padding: 15% 0;\n    float: left;\n}\n\n#messages {\n    float: right;\n}\n  \n"
  },
  {
    "path": "examples/timer/src/main.rs",
    "content": "use gloo::console::{self, Timer};\nuse gloo::timers::callback::{Interval, Timeout};\nuse yew::prelude::*;\n\npub enum Msg {\n    StartTimeout,\n    StartInterval,\n    Cancel,\n    Done,\n    Tick,\n    UpdateTime,\n}\n\npub struct App {\n    time: String,\n    messages: Vec<AttrValue>,\n    _standalone: (Interval, Interval),\n    interval: Option<Interval>,\n    timeout: Option<Timeout>,\n    console_timer: Option<Timer<'static>>,\n}\n\nimpl App {\n    fn get_current_time() -> String {\n        let date = js_sys::Date::new_0();\n        String::from(date.to_locale_time_string(\"en-US\"))\n    }\n\n    fn cancel(&mut self) {\n        self.timeout = None;\n        self.interval = None;\n    }\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let standalone_handle =\n            Interval::new(10, || console::debug!(\"Example of a standalone callback.\"));\n\n        let clock_handle = {\n            let link = ctx.link().clone();\n            Interval::new(1, move || link.send_message(Msg::UpdateTime))\n        };\n\n        Self {\n            time: App::get_current_time(),\n            messages: Vec::new(),\n            _standalone: (standalone_handle, clock_handle),\n            interval: None,\n            timeout: None,\n            console_timer: None,\n        }\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::StartTimeout => {\n                let handle = {\n                    let link = ctx.link().clone();\n                    Timeout::new(3000, move || link.send_message(Msg::Done))\n                };\n\n                self.timeout = Some(handle);\n\n                self.messages.clear();\n                console::clear!();\n\n                self.log(\"Timer started!\");\n                self.console_timer = Some(Timer::new(\"Timer\"));\n                true\n            }\n            Msg::StartInterval => {\n                let handle = {\n                    let link = ctx.link().clone();\n                    Interval::new(1000, move || link.send_message(Msg::Tick))\n                };\n                self.interval = Some(handle);\n\n                self.messages.clear();\n                console::clear!();\n\n                self.log(\"Interval started!\");\n                true\n            }\n            Msg::Cancel => {\n                self.cancel();\n                self.log(\"Canceled!\");\n                console::warn!(\"Canceled!\");\n                true\n            }\n            Msg::Done => {\n                self.cancel();\n                self.log(\"Done!\");\n\n                // todo weblog\n                // ConsoleService::group();\n                console::info!(\"Done!\");\n                if let Some(timer) = self.console_timer.take() {\n                    drop(timer);\n                }\n\n                // todo weblog\n                // ConsoleService::group_end();\n                true\n            }\n            Msg::Tick => {\n                self.log(\"Tick...\");\n                // todo weblog\n                // ConsoleService::count_named(\"Tick\");\n                true\n            }\n            Msg::UpdateTime => {\n                self.time = App::get_current_time();\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let has_job = self.timeout.is_some() || self.interval.is_some();\n        html! {\n            <>\n                <div id=\"buttons\">\n                    <button disabled={has_job} onclick={ctx.link().callback(|_| Msg::StartTimeout)}>\n                        { \"Start Timeout\" }\n                    </button>\n                    <button disabled={has_job} onclick={ctx.link().callback(|_| Msg::StartInterval)}>\n                        { \"Start Interval\" }\n                    </button>\n                    <button disabled={!has_job} onclick={ctx.link().callback(|_| Msg::Cancel)}>\n                        { \"Cancel!\" }\n                    </button>\n                </div>\n                <div id=\"wrapper\">\n                    <div id=\"time\">\n                        { &self.time }\n                    </div>\n                    <div id=\"messages\">\n                        { for self.messages.iter().map(|message| html! { <p>{ message }</p> }) }\n                    </div>\n                </div>\n            </>\n        }\n    }\n}\n\nimpl App {\n    fn log(&mut self, message: impl Into<AttrValue>) {\n        self.messages.push(message.into());\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/timer_functional/Cargo.toml",
    "content": "[package]\nname = \"timer_functional\"\nversion = \"0.1.0\"\nauthors = [\"Zahash <zahash.z@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\ngloo.workspace = true\njs-sys.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n"
  },
  {
    "path": "examples/timer_functional/README.md",
    "content": "# Timer Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ftimer_functional)](https://examples.yew.rs/timer_functional)\n\nThis is a technical demonstration for how to use timeouts and intervals.\n\n## Concepts\n\nThe example mainly demonstrates the use of [`gloo_timer`](https://docs.rs/gloo-timers/ ) but does so using only [`function components`](https://yew.rs/docs/concepts/function-components).\n\n## Running\n\nRun a debug version of this application:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/timer_functional/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/timer_functional/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Yew • Timer</title>\n  <link data-trunk rel=\"scss\" href=\"index.scss\"/>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@900&display=swap\" rel=\"stylesheet\">\n  <link data-trunk rel=\"rust\" />\n</head>\n\n<body></body>\n\n</html>\n"
  },
  {
    "path": "examples/timer_functional/index.scss",
    "content": "$font-stack:    Roboto, sans-serif;\n$primary-color: #008f53;\n\nbody {\n    font: 100% $font-stack;\n    color: white;\n    background-color: $primary-color;\n}\n\n#buttons {\n    text-align: right;\n}\n\n#wrapper {\n    overflow: hidden;\n    width: 100%;\n}\n\n#time {\n    text-align: center;\n    font-size: 17vh;\n    padding: 15% 0;\n    float: left;\n}\n\n#messages {\n    float: right;\n}\n  \n"
  },
  {
    "path": "examples/timer_functional/src/main.rs",
    "content": "use std::rc::Rc;\n\nuse gloo::timers::callback::{Interval, Timeout};\nuse yew::prelude::*;\n\nfn get_current_time() -> String {\n    let date = js_sys::Date::new_0();\n    String::from(date.to_locale_time_string(\"en-US\"))\n}\n\nenum TimerAction {\n    Add(&'static str),\n    Cancel,\n    SetInterval(Interval),\n    SetTimeout(Timeout),\n    TimeoutDone,\n}\n\n#[derive(Clone, Debug)]\nstruct TimerState {\n    messages: Messages,\n    interval_handle: Option<Rc<Interval>>,\n    timeout_handle: Option<Rc<Timeout>>,\n}\n\n#[derive(Clone, Debug, Default, PartialEq, Eq)]\nstruct Messages(Vec<AttrValue>);\n\nimpl Messages {\n    fn log(&mut self, message: impl Into<AttrValue>) {\n        self.0.push(message.into());\n    }\n}\n\nimpl std::ops::Deref for Messages {\n    type Target = Vec<AttrValue>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl FromIterator<&'static str> for Messages {\n    fn from_iter<T: IntoIterator<Item = &'static str>>(it: T) -> Self {\n        Messages(it.into_iter().map(Into::into).collect())\n    }\n}\n\nimpl PartialEq for TimerState {\n    fn eq(&self, other: &Self) -> bool {\n        self.messages == other.messages\n            && self.interval_handle.is_some() == other.interval_handle.is_some()\n    }\n}\n\nimpl Reducible for TimerState {\n    type Action = TimerAction;\n\n    fn reduce(self: Rc<Self>, action: TimerAction) -> Rc<Self> {\n        match action {\n            TimerAction::Add(message) => {\n                let mut messages = self.messages.clone();\n                messages.log(message);\n                Rc::new(TimerState {\n                    messages,\n                    interval_handle: self.interval_handle.clone(),\n                    timeout_handle: self.timeout_handle.clone(),\n                })\n            }\n            TimerAction::SetInterval(t) => Rc::new(TimerState {\n                messages: [\"Interval started!\"].into_iter().collect(),\n                interval_handle: Some(Rc::from(t)),\n                timeout_handle: self.timeout_handle.clone(),\n            }),\n            TimerAction::SetTimeout(t) => Rc::new(TimerState {\n                messages: [\"Timer started!!\"].into_iter().collect(),\n                interval_handle: self.interval_handle.clone(),\n                timeout_handle: Some(Rc::from(t)),\n            }),\n            TimerAction::TimeoutDone => {\n                let mut messages = self.messages.clone();\n                messages.log(\"Done!\");\n                Rc::new(TimerState {\n                    messages,\n                    interval_handle: self.interval_handle.clone(),\n                    timeout_handle: None,\n                })\n            }\n            TimerAction::Cancel => {\n                let mut messages = self.messages.clone();\n                messages.log(\"Canceled!\");\n                Rc::new(TimerState {\n                    messages,\n                    interval_handle: None,\n                    timeout_handle: None,\n                })\n            }\n        }\n    }\n}\n\n#[function_component(Clock)]\nfn clock() -> Html {\n    let time = use_state(get_current_time);\n\n    {\n        let time = time.clone();\n        use_effect_with((), |_| {\n            Interval::new(1000, move || time.set(get_current_time())).forget();\n        });\n    }\n    html!(\n        <div id=\"time\">{ time.as_str() }</div>\n    )\n}\n\n#[function_component]\nfn App() -> Html {\n    let state = use_reducer(|| TimerState {\n        messages: Default::default(),\n        interval_handle: None,\n        timeout_handle: None,\n    });\n\n    let mut key = 0;\n    let messages: Html = state\n        .messages\n        .iter()\n        .map(|message| {\n            key += 1;\n            html! { <p {key}>{ message }</p> }\n        })\n        .collect();\n\n    let has_job = state.interval_handle.is_some() || state.timeout_handle.is_some();\n\n    let on_add_timeout = {\n        let state = state.clone();\n\n        Callback::from(move |_: MouseEvent| {\n            let timeout_state = state.clone();\n            let message_state = state.clone();\n            let t = Timeout::new(3000, move || {\n                message_state.dispatch(TimerAction::TimeoutDone);\n            });\n\n            timeout_state.dispatch(TimerAction::SetTimeout(t));\n        })\n    };\n\n    let on_add_interval = {\n        let state = state.clone();\n\n        Callback::from(move |_: MouseEvent| {\n            let interval_state = state.clone();\n            let message_state = state.clone();\n            let i = Interval::new(1000, move || {\n                message_state.dispatch(TimerAction::Add(\"Tick..\"));\n            });\n\n            interval_state.dispatch(TimerAction::SetInterval(i));\n        })\n    };\n\n    let on_cancel = {\n        Callback::from(move |_: MouseEvent| {\n            state.dispatch(TimerAction::Cancel);\n        })\n    };\n\n    html!(\n        <>\n            <div id=\"buttons\">\n                <button disabled={has_job} onclick={on_add_timeout}>{ \"Start Timeout\" }</button>\n                <button disabled={has_job} onclick={on_add_interval}>{ \"Start Interval\" }</button>\n                <button disabled={!has_job} onclick={on_cancel}>{ \"Cancel\"}</button>\n            </div>\n            <div id=\"wrapper\">\n                <Clock />\n                <div id=\"messages\">\n                    { messages }\n                </div>\n            </div>\n        </>\n    )\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/todomvc/Cargo.toml",
    "content": "[package]\nname = \"todomvc\"\nversion = \"0.1.0\"\nauthors = [\"Denis Kolodin <deniskolodin@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nstrum.workspace = true\nstrum_macros.workspace = true\nserde.workspace = true\nserde_derive = \"1\"\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n\t\"HtmlInputElement\",\n]\n"
  },
  {
    "path": "examples/todomvc/README.md",
    "content": "# TodoMVC Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ftodomvc)](https://examples.yew.rs/todomvc)\n\nThis is an implementation of [TodoMVC](http://todomvc.com/) for Yew.\n\nUnlike other implementations, this stores the full state of the model,\nincluding: all entries, entered text and chosen filter.\n\n## Concepts\n\n- Uses [`gloo_storage`](https://docs.rs/gloo-storage/latest/gloo_storage/) to persist the state\n- [`Refs`] are used to manipulate DOM elements after they're rendered (to automatically focus input fields for instance)\n\n## Improvements\n\n- Use `yew-router` for the hash based routing\n- Clean up the code\n\n[`refs`]: https://yew.rs/docs/concepts/components/refs/\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/todomvc/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/todomvc/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>Yew • TodoMVC</title>\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.css\"\n    />\n    <link\n      rel=\"stylesheet\"\n      href=\"https://cdn.jsdelivr.net/npm/todomvc-app-css@2.3.0/index.css\"\n    />\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/todomvc/src/main.rs",
    "content": "use gloo::storage::{LocalStorage, Storage};\nuse state::{Entry, Filter, State};\nuse strum::IntoEnumIterator;\nuse web_sys::HtmlInputElement as InputElement;\nuse yew::events::{FocusEvent, KeyboardEvent};\nuse yew::html::Scope;\nuse yew::{classes, html, Classes, Component, Context, Html, NodeRef, TargetCast};\n\nmod state;\n\nconst KEY: &str = \"yew.todomvc.self\";\n\npub enum Msg {\n    Add(String),\n    Edit((usize, String)),\n    Remove(usize),\n    SetFilter(Filter),\n    ToggleAll,\n    ToggleEdit(usize),\n    Toggle(usize),\n    ClearCompleted,\n    Focus,\n}\n\npub struct App {\n    state: State,\n    focus_ref: NodeRef,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        let entries = LocalStorage::get(KEY).unwrap_or_else(|_| Vec::new());\n        let state = State::new(entries);\n        let focus_ref = NodeRef::default();\n        Self { state, focus_ref }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Add(description) => {\n                let description = description.trim();\n                if !description.is_empty() {\n                    let entry = Entry {\n                        description: description.to_string(),\n                        completed: false,\n                        editing: false,\n                    };\n                    self.state.entries.push(entry);\n                }\n            }\n            Msg::Edit((idx, edit_value)) => {\n                self.state.complete_edit(idx, edit_value.trim().to_string());\n                self.state.edit_value = \"\".to_string();\n            }\n            Msg::Remove(idx) => {\n                self.state.remove(idx);\n            }\n            Msg::SetFilter(filter) => {\n                self.state.filter = filter;\n            }\n            Msg::ToggleEdit(idx) => {\n                let entry = self.state.entries.get(idx).unwrap();\n                self.state.edit_value.clone_from(&entry.description);\n                self.state.clear_all_edit();\n                self.state.toggle_edit(idx);\n            }\n            Msg::ToggleAll => {\n                let status = !self.state.is_all_completed();\n                self.state.set_completed(status);\n            }\n            Msg::Toggle(idx) => {\n                self.state.toggle_completed(idx);\n            }\n            Msg::ClearCompleted => {\n                self.state.clear_completed();\n            }\n            Msg::Focus => {\n                if let Some(input) = self.focus_ref.cast::<InputElement>() {\n                    input.focus().unwrap();\n                }\n            }\n        }\n        LocalStorage::set(KEY, &self.state.entries).expect(\"failed to set\");\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let hidden_class = if self.state.entries.is_empty() {\n            \"hidden\"\n        } else {\n            \"\"\n        };\n        html! {\n            <div class=\"todomvc-wrapper\">\n                <section class=\"todoapp\">\n                    <header class=\"header\">\n                        <h1>{ \"todos\" }</h1>\n                        { self.view_input(ctx.link()) }\n                    </header>\n                    <section class={classes!(\"main\", hidden_class)}>\n                        <input\n                            type=\"checkbox\"\n                            class=\"toggle-all\"\n                            id=\"toggle-all\"\n                            checked={self.state.is_all_completed()}\n                            onclick={ctx.link().callback(|_| Msg::ToggleAll)}\n                        />\n                        <label for=\"toggle-all\" />\n                        <ul class=\"todo-list\">\n                            { for self\n                                .state\n                                .entries\n                                .iter()\n                                .enumerate()\n                                .filter(|(_, entry)| self.state.filter.fits(entry))\n                                .map(|(i, e)| self.view_entry((i, e), ctx.link()))\n                            }\n                        </ul>\n                    </section>\n                    <footer class={classes!(\"footer\", hidden_class)}>\n                        <span class=\"todo-count\">\n                            <strong>{ self.state.total() }</strong>\n                            { \" item(s) left\" }\n                        </span>\n                        <ul class=\"filters\">\n                            { for Filter::iter().map(|flt| self.view_filter(flt, ctx.link())) }\n                        </ul>\n                        <button class=\"clear-completed\" onclick={ctx.link().callback(|_| Msg::ClearCompleted)}>\n                            { format!(\"Clear completed ({})\", self.state.total_completed()) }\n                        </button>\n                    </footer>\n                </section>\n                <footer class=\"info\">\n                    <p>{ \"Double-click to edit a todo\" }</p>\n                    <p>{ \"Written by \" }<a href=\"https://github.com/DenisKolodin/\" target=\"_blank\">{ \"Denis Kolodin\" }</a></p>\n                    <p>{ \"Part of \" }<a href=\"http://todomvc.com/\" target=\"_blank\">{ \"TodoMVC\" }</a></p>\n                </footer>\n            </div>\n        }\n    }\n}\n\nimpl App {\n    fn view_filter(&self, filter: Filter, link: &Scope<Self>) -> Html {\n        let cls = if self.state.filter == filter {\n            \"selected\"\n        } else {\n            \"not-selected\"\n        };\n        html! {\n            <li>\n                <a class={cls}\n                   href={filter.as_href()}\n                   onclick={link.callback(move |_| Msg::SetFilter(filter))}\n                >\n                    { filter }\n                </a>\n            </li>\n        }\n    }\n\n    fn view_input(&self, link: &Scope<Self>) -> Html {\n        let onkeypress = link.batch_callback(|e: KeyboardEvent| {\n            if e.key() == \"Enter\" {\n                let input: InputElement = e.target_unchecked_into();\n                let value = input.value();\n                input.set_value(\"\");\n                Some(Msg::Add(value))\n            } else {\n                None\n            }\n        });\n        html! {\n            // You can use standard Rust comments. One line:\n            // <li></li>\n            <input\n                class=\"new-todo\"\n                placeholder=\"What needs to be done?\"\n                {onkeypress}\n            />\n            /* Or multiline:\n            <ul>\n                <li></li>\n            </ul>\n            */\n        }\n    }\n\n    fn view_entry(&self, (idx, entry): (usize, &Entry), link: &Scope<Self>) -> Html {\n        let mut class = Classes::from(\"todo\");\n        if entry.editing {\n            class.push(\" editing\");\n        }\n        if entry.completed {\n            class.push(\" completed\");\n        }\n        html! {\n            <li {class}>\n                <div class=\"view\">\n                    <input\n                        type=\"checkbox\"\n                        class=\"toggle\"\n                        checked={entry.completed}\n                        onclick={link.callback(move |_| Msg::Toggle(idx))}\n                    />\n                    <label ondblclick={link.callback(move |_| Msg::ToggleEdit(idx))}>{ &entry.description }</label>\n                    <button class=\"destroy\" onclick={link.callback(move |_| Msg::Remove(idx))} />\n                </div>\n                { self.view_entry_edit_input((idx, entry), link) }\n            </li>\n        }\n    }\n\n    fn view_entry_edit_input(&self, (idx, entry): (usize, &Entry), link: &Scope<Self>) -> Html {\n        let edit = move |input: InputElement| {\n            let value = input.value();\n            input.set_value(\"\");\n            Msg::Edit((idx, value))\n        };\n\n        let onblur = link.callback(move |e: FocusEvent| edit(e.target_unchecked_into()));\n\n        let onkeypress = link.batch_callback(move |e: KeyboardEvent| {\n            (e.key() == \"Enter\").then(|| edit(e.target_unchecked_into()))\n        });\n\n        if entry.editing {\n            html! {\n                <input\n                    class=\"edit\"\n                    type=\"text\"\n                    ref={self.focus_ref.clone()}\n                    value={self.state.edit_value.clone()}\n                    onmouseover={link.callback(|_| Msg::Focus)}\n                    {onblur}\n                    {onkeypress}\n                />\n            }\n        } else {\n            html! { <input type=\"hidden\" /> }\n        }\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "examples/todomvc/src/state.rs",
    "content": "use serde_derive::{Deserialize, Serialize};\nuse strum_macros::{Display, EnumIter};\nuse yew::html::IntoPropValue;\nuse yew::prelude::*;\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct State {\n    pub entries: Vec<Entry>,\n    pub filter: Filter,\n    pub edit_value: String,\n}\n\nimpl State {\n    pub fn new(entries: Vec<Entry>) -> Self {\n        Self {\n            entries,\n            filter: Filter::All,\n            edit_value: \"\".into(),\n        }\n    }\n\n    pub fn total(&self) -> usize {\n        self.entries.len()\n    }\n\n    pub fn total_completed(&self) -> usize {\n        self.entries\n            .iter()\n            .filter(|e| Filter::Completed.fits(e))\n            .count()\n    }\n\n    pub fn is_all_completed(&self) -> bool {\n        let mut filtered_iter = self\n            .entries\n            .iter()\n            .filter(|e| self.filter.fits(e))\n            .peekable();\n\n        if filtered_iter.peek().is_none() {\n            return false;\n        }\n\n        filtered_iter.all(|e| e.completed)\n    }\n\n    pub fn clear_completed(&mut self) {\n        self.entries.retain(|e| Filter::Active.fits(e));\n    }\n\n    pub fn toggle_completed(&mut self, idx: usize) {\n        let entry = self.entries.get_mut(idx).unwrap();\n        entry.completed = !entry.completed;\n    }\n\n    pub fn set_completed(&mut self, value: bool) {\n        for entry in &mut self.entries {\n            if self.filter.fits(entry) {\n                entry.completed = value;\n            }\n        }\n    }\n\n    pub fn toggle_edit(&mut self, idx: usize) {\n        let entry = self.entries.get_mut(idx).unwrap();\n        entry.editing = !entry.editing;\n    }\n\n    pub fn clear_all_edit(&mut self) {\n        for entry in &mut self.entries {\n            entry.editing = false;\n        }\n    }\n\n    pub fn complete_edit(&mut self, idx: usize, val: String) {\n        if val.is_empty() {\n            self.remove(idx);\n        } else {\n            let entry = self.entries.get_mut(idx).unwrap();\n            entry.description = val;\n            entry.editing = !entry.editing;\n        }\n    }\n\n    pub fn remove(&mut self, idx: usize) {\n        self.entries.remove(idx);\n    }\n}\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Entry {\n    pub description: String,\n    pub completed: bool,\n    pub editing: bool,\n}\n\n#[derive(Clone, Copy, Debug, EnumIter, Display, PartialEq, Serialize, Deserialize, Eq)]\npub enum Filter {\n    All,\n    Active,\n    Completed,\n}\nimpl Filter {\n    pub fn fits(&self, entry: &Entry) -> bool {\n        match *self {\n            Filter::All => true,\n            Filter::Active => !entry.completed,\n            Filter::Completed => entry.completed,\n        }\n    }\n\n    pub fn as_href(&self) -> &'static str {\n        match self {\n            Filter::All => \"#/\",\n            Filter::Active => \"#/active\",\n            Filter::Completed => \"#/completed\",\n        }\n    }\n}\n\nimpl IntoPropValue<Html> for Filter {\n    fn into_prop_value(self) -> yew::Html {\n        html! { <>{self.to_string()}</> }\n    }\n}\n"
  },
  {
    "path": "examples/two_apps/Cargo.toml",
    "content": "[package]\nname = \"two_apps\"\nversion = \"0.1.0\"\nauthors = [\"Denis Kolodin <deniskolodin@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\ngloo.workspace = true\n"
  },
  {
    "path": "examples/two_apps/README.md",
    "content": "# Two Apps Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Ftwo_apps)](https://examples.yew.rs/two_apps)\n\nThis example runs two Yew apps which communicate with each other.\n\n## Concepts\n\nThe example illustrates how one can take control of the mounting process which is usually done by `yew::start_app`.\n\n## Improvements\n\nInstead of using the same component type twice, the example could use two entirely different components that communicate with each other.\nOne of the components could even accept a generic \"remote\" component using a trait.\n\nThis example is very similar to [`mount_point`](../mount_point).\nThe two should be merged into a single example.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/two_apps/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/two_apps/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • Two Apps</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n  <body>\n    <div class=\"first-app\"></div>\n    <div class=\"second-app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/two_apps/src/main.rs",
    "content": "use yew::html::Scope;\nuse yew::{html, AppHandle, Component, Context, Html};\n\npub enum Msg {\n    SetOpposite(Scope<App>),\n    SendToOpposite(String),\n    SetTitle(String),\n}\n\npub struct App {\n    opposite: Option<Scope<App>>,\n    selector: &'static str,\n    title: String,\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        App {\n            opposite: None,\n            selector: \"\",\n            title: \"Nothing\".to_owned(),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetOpposite(opposite) => {\n                self.opposite = Some(opposite);\n                false\n            }\n            Msg::SendToOpposite(title) => {\n                self.opposite\n                    .as_mut()\n                    .unwrap()\n                    .send_message(Msg::SetTitle(title));\n                false\n            }\n            Msg::SetTitle(title) => {\n                let send_msg = match title.as_ref() {\n                    \"Ping\" => Some(Msg::SetTitle(\"Pong\".into())),\n                    \"Pong\" => Some(Msg::SetTitle(\"Pong Done\".into())),\n                    \"Pong Done\" => Some(Msg::SetTitle(\"Ping Done\".into())),\n                    _ => None,\n                };\n\n                if let Some(send_msg) = send_msg {\n                    self.opposite.as_mut().unwrap().send_message(send_msg);\n                }\n\n                self.title = title;\n                true\n            }\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div>\n                <h3>{ format!(\"{} received <{}>\", self.selector, self.title) }</h3>\n                <button onclick={ctx.link().callback(|_| Msg::SendToOpposite(\"One\".into()))}>{ \"One\" }</button>\n                <button onclick={ctx.link().callback(|_| Msg::SendToOpposite(\"Two\".into()))}>{ \"Two\" }</button>\n                <button onclick={ctx.link().callback(|_| Msg::SendToOpposite(\"Three\".into()))}>{ \"Three\" }</button>\n                <button onclick={ctx.link().callback(|_| Msg::SendToOpposite(\"Ping\".into()))}>{ \"Ping\" }</button>\n            </div>\n        }\n    }\n}\n\nfn mount_app(selector: &'static str) -> AppHandle<App> {\n    let document = gloo::utils::document();\n    let element = document.query_selector(selector).unwrap().unwrap();\n    yew::Renderer::<App>::with_root(element).render()\n}\n\nfn main() {\n    let first_app = mount_app(\".first-app\");\n    let second_app = mount_app(\".second-app\");\n\n    first_app.send_message(Msg::SetOpposite(second_app.clone()));\n    second_app.send_message(Msg::SetOpposite(first_app.clone()));\n}\n"
  },
  {
    "path": "examples/wasi_ssr_module/Cargo.toml",
    "content": "[package]\nname = \"wasi_ssr_module\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"langyo <langyo.china@gmail.com>\"]\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"ssr\"] }\nyew-router = { path = \"../../packages/yew-router\" }\n\nanyhow = \"^1\"\nbytes = \"1\"\nserde = { version = \"^1\", features = [\"derive\"] }\nserde_json = \"^1\"\nlazy_static = \"^1\"\n\ntokio = { workspace = true, features = [\"macros\", \"rt\", \"time\"] }\n"
  },
  {
    "path": "examples/wasi_ssr_module/README.md",
    "content": "# WASI SSR Module Example\n\nThis example demonstrates how to use the WASI target to run a simple server-side rendering application.\n\nIt depends on [wasmtime](https://wasmtime.dev)'s WASI preview2.\n\n## Building\n\nTo build the example, run the following command from the root of the repository:\n\n```bash\ncargo build --manifest-path examples/wasi_ssr_module/Cargo.toml --target wasm32-wasip1 --release\n```\n\n## Running\n\n> Note: This example requires the wasmtime CLI to be installed. See [wasmtime's installation instructions](https://docs.wasmtime.dev/cli-install.html) for more information.\n\n```bash\nwasmtime target/wasm32-wasip1/release/wasi_ssr_module.wasm\n```\n\n> Note: If your wasmtime CLI throws an error that it says some imports like `__wbindgen_placeholder__::__wbindgen_xxx` is invalid, try to run `cargo update`. See issue [rustwasm/gloo#411](https://github.com/rustwasm/gloo/pull/411#discussion_r1421219033).\n"
  },
  {
    "path": "examples/wasi_ssr_module/src/main.rs",
    "content": "#![allow(unused_imports)]\n#![allow(non_snake_case)]\n\nmod router;\n\nuse anyhow::Result;\nuse router::{switch, Route};\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[function_component]\nfn Content() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n            <Switch<Route> render={switch} />\n        </>\n    }\n}\n\n#[function_component]\nfn App() -> Html {\n    use yew_router::history::{AnyHistory, History, MemoryHistory};\n    use yew_router::prelude::*;\n\n    let history = AnyHistory::from(MemoryHistory::new());\n    history.push(\"/\");\n\n    html! {\n        <div>\n            <Router history={history}>\n                <Content />\n            </Router>\n        </div>\n    }\n}\n\npub async fn render() -> Result<String> {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app' style='width: 100vw; height: 100vh; position: fixed;'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    Ok(body)\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> Result<()> {\n    let ret = render().await?;\n    println!(\"{ret}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/wasi_ssr_module/src/router.rs",
    "content": "use yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Routable, PartialEq, Eq, Clone, Debug)]\npub enum Route {\n    #[at(\"/\")]\n    Portal,\n\n    #[at(\"/t/:id\")]\n    Thread { id: String },\n\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\npub fn switch(routes: Route) -> Html {\n    match routes {\n        Route::Portal => {\n            html! { <h1>{\"Hello\"}</h1> }\n        }\n        Route::Thread { id } => {\n            html! { <h1>{format!(\"Thread id {}\", id)}</h1> }\n        }\n        Route::NotFound => {\n            html! { <h1>{\"Not found\"}</h1> }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/web_worker_fib/Cargo.toml",
    "content": "[package]\nname = \"yew-worker-fib\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Shrey Somaiya\", \"Zac Kologlu\"]\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nyew-agent = { path = \"../../packages/yew-agent\" }\nwasm-bindgen.workspace = true\njs-sys.workspace = true\nweb-sys = { workspace = true, features = [ \"HtmlInputElement\" ] }\nserde = { workspace = true, features = [\"derive\"] }\npostcard = \"1.0.10\"\n"
  },
  {
    "path": "examples/web_worker_fib/README.md",
    "content": "# Web Worker Fib\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fweb_worker_fib)](https://examples.yew.rs/web_worker_fib)\n\nCalculate fibrillation value of a number in the worker thread, without blocking the main thread.\n\n## Concepts\n\nThe example illustrates how to use `yew-agent` to send tasks to a worker thread in a Yew application.\n\n## Thanks to\n\n- [insou22](https://github.com/insou22) for writing up the demo.\n- [https://github.com/yvt/img2text](https://github.com/yvt/img2text) -- for how to make web workers compile in wasm\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/web_worker_fib/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/web_worker_fib/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Yew • Web Worker Fibonacci</title>\n\n    <link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-bin=\"app\" data-type=\"main\" data-weak-refs />\n    <link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-bin=\"worker\" data-type=\"worker\" data-weak-refs />\n</head>\n\n<body>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/web_worker_fib/src/agent.rs",
    "content": "use js_sys::Uint8Array;\nuse serde::{Deserialize, Serialize};\nuse wasm_bindgen::JsValue;\nuse yew_agent::prelude::*;\nuse yew_agent::Codec;\n\n/// Example to use a custom codec.\npub struct Postcard;\n\nimpl Codec for Postcard {\n    fn encode<I>(input: I) -> JsValue\n    where\n        I: Serialize,\n    {\n        let buf = postcard::to_vec::<_, 32>(&input).expect(\"can't serialize a worker message\");\n        Uint8Array::from(buf.as_slice()).into()\n    }\n\n    fn decode<O>(input: JsValue) -> O\n    where\n        O: for<'de> Deserialize<'de>,\n    {\n        let data = Uint8Array::from(input).to_vec();\n        postcard::from_bytes(&data).expect(\"can't deserialize a worker message\")\n    }\n}\n\n#[oneshot]\npub async fn FibonacciTask(n: u32) -> u32 {\n    fn fib(n: u32) -> u32 {\n        if n <= 1 {\n            1\n        } else {\n            fib(n - 1) + fib(n - 2)\n        }\n    }\n\n    fib(n)\n}\n"
  },
  {
    "path": "examples/web_worker_fib/src/bin/app.rs",
    "content": "fn main() {\n    yew::Renderer::<yew_worker_fib::App>::new().render();\n}\n"
  },
  {
    "path": "examples/web_worker_fib/src/bin/worker.rs",
    "content": "use yew_agent::Registrable;\nuse yew_worker_fib::agent::{FibonacciTask, Postcard};\n\nfn main() {\n    FibonacciTask::registrar().encoding::<Postcard>().register();\n}\n"
  },
  {
    "path": "examples/web_worker_fib/src/lib.rs",
    "content": "#![recursion_limit = \"1024\"]\n#![allow(clippy::large_enum_variant)]\n\npub mod agent;\n\nuse web_sys::HtmlInputElement;\nuse yew::platform::spawn_local;\nuse yew::prelude::*;\nuse yew_agent::oneshot::{use_oneshot_runner, OneshotProvider};\n\nuse crate::agent::{FibonacciTask, Postcard};\n\n#[function_component]\nfn Main() -> Html {\n    let input_value = use_state_eq(|| 44);\n    let output = use_state(|| \"Try out some fibonacci calculations!\".to_string());\n    let fib_task = use_oneshot_runner::<FibonacciTask>();\n\n    let clicker_value = use_state_eq(|| 0);\n\n    let calculate = {\n        let input_value = *input_value;\n        let output = output.clone();\n        move |_e: MouseEvent| {\n            let fib_agent = fib_task.clone();\n            let output = output.clone();\n\n            spawn_local(async move {\n                // start the worker\n                let output_value = fib_agent.run(input_value).await;\n\n                output.set(format!(\"Fibonacci value: {output_value}\"));\n            });\n        }\n    };\n\n    let on_input_change = {\n        let input_value = input_value.clone();\n        move |e: InputEvent| {\n            input_value.set(\n                e.target_unchecked_into::<HtmlInputElement>()\n                    .value()\n                    .parse()\n                    .expect(\"failed to parse\"),\n            );\n        }\n    };\n\n    let inc_clicker = {\n        let clicker_value = clicker_value.clone();\n\n        move |_e: MouseEvent| {\n            clicker_value.set(*clicker_value + 1);\n        }\n    };\n\n    html! {\n        <>\n            <h1>{ \"Web worker demo\" }</h1>\n            <p>{ \"Submit a value to calculate, then increase the counter on the main thread!\"} </p>\n            <p>{ \"Large numbers will take some time!\" }</p>\n            <h3>{ \"Output: \" } { &*output }</h3>\n            <br />\n            <input type=\"number\" value={input_value.to_string()} max=\"50\" oninput={on_input_change} />\n            <button onclick={calculate}>{ \"submit\" }</button>\n            <br /> <br />\n            <h3>{ \"Main thread value: \" } { *clicker_value }</h3>\n            <button onclick={inc_clicker}>{ \"click!\" }</button>\n        </>\n    }\n}\n\n#[function_component]\npub fn App() -> Html {\n    html! {\n        <OneshotProvider<FibonacciTask, Postcard> path=\"/worker.js\">\n            <Main />\n        </OneshotProvider<FibonacciTask, Postcard>>\n    }\n}\n"
  },
  {
    "path": "examples/web_worker_prime/Cargo.toml",
    "content": "[package]\nname = \"yew-worker-prime\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew-agent = { path = \"../../packages/yew-agent\" }\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\nfutures.workspace = true\nprimes = \"0.4.0\"\nserde = { workspace = true, features = [\"derive\"] }\n"
  },
  {
    "path": "examples/web_worker_prime/README.md",
    "content": "# Web Worker Prime\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fweb_worker_prime)](https://examples.yew.rs/web_worker_prime)\n\nCalculate primes until stop button is pressed, without blocking the main thread.\n\n## Concepts\n\nThe example illustrates how to use reactor agents to offload CPU bound tasks to a worker thread in a Yew application.\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```\n"
  },
  {
    "path": "examples/web_worker_prime/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/web_worker_prime/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <title>Yew • Web Worker Prime</title>\n\n    <link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-bin=\"app\" data-type=\"main\" data-weak-refs />\n    <link data-trunk rel=\"rust\" href=\"Cargo.toml\" data-bin=\"worker\" data-type=\"worker\" data-weak-refs />\n</head>\n\n<body>\n</body>\n\n</html>\n"
  },
  {
    "path": "examples/web_worker_prime/src/agent.rs",
    "content": "use std::time::Duration;\n\nuse futures::sink::SinkExt;\nuse futures::{FutureExt, StreamExt};\nuse serde::{Deserialize, Serialize};\nuse yew::platform::time::sleep;\nuse yew_agent::prelude::*;\n\n#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]\npub enum ControlSignal {\n    Start,\n    Stop,\n}\n\n#[reactor]\npub async fn PrimeReactor(mut scope: ReactorScope<ControlSignal, u64>) {\n    while let Some(m) = scope.next().await {\n        if m == ControlSignal::Start {\n            'inner: for i in 1.. {\n                // This is not the most efficient way to calculate prime,\n                // but this example is here to demonstrate how primes can be\n                // sent to the application in an ascending order.\n                if primes::is_prime(i) {\n                    scope.send(i).await.unwrap();\n                }\n\n                futures::select! {\n                    m = scope.next() => {\n                        if m == Some(ControlSignal::Stop) {\n                            break 'inner;\n                        }\n                    },\n                    _ = sleep(Duration::from_millis(100)).fuse() => {},\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/web_worker_prime/src/bin/app.rs",
    "content": "fn main() {\n    yew::Renderer::<yew_worker_prime::App>::new().render();\n}\n"
  },
  {
    "path": "examples/web_worker_prime/src/bin/worker.rs",
    "content": "use yew_agent::Registrable;\nuse yew_worker_prime::agent::PrimeReactor;\n\nfn main() {\n    PrimeReactor::registrar().register();\n}\n"
  },
  {
    "path": "examples/web_worker_prime/src/lib.rs",
    "content": "pub mod agent;\nuse agent::{ControlSignal, PrimeReactor};\nuse yew::prelude::*;\nuse yew_agent::reactor::{use_reactor_subscription, ReactorProvider};\n\n#[function_component]\nfn Main() -> Html {\n    let prime_sub = use_reactor_subscription::<PrimeReactor>();\n    let started = use_state_eq(|| false);\n    let skip_len = use_state_eq(|| 0);\n\n    let result_s = prime_sub\n        .iter()\n        // Skip results in previous runs.\n        .skip(*skip_len)\n        .fold(\"\".to_string(), |mut output, item| {\n            if !output.is_empty() {\n                output.push_str(\", \");\n            }\n\n            output.push_str(&item.to_string());\n\n            output\n        });\n\n    let start_prime_calc = use_callback(\n        (prime_sub.clone(), started.setter(), skip_len.setter()),\n        |_input, (prime_sub, started_setter, skip_len)| {\n            skip_len.set(prime_sub.len());\n            prime_sub.send(ControlSignal::Start);\n            started_setter.set(true);\n        },\n    );\n\n    let stop_prime_calc = use_callback(\n        (prime_sub, started.setter()),\n        |_input, (prime_sub, started_setter)| {\n            prime_sub.send(ControlSignal::Stop);\n            started_setter.set(false);\n        },\n    );\n\n    html! {\n        <>\n            <h1>{\"Find Prime\"}</h1>\n            <p>{\"This page demonstrates how to calculate prime in a web worker.\"}</p>\n            if *started {\n                <button onclick={stop_prime_calc}>{\"Stop\"}</button>\n            } else {\n                <button onclick={start_prime_calc}>{\"Start\"}</button>\n            }\n            <div id=\"result\">{result_s}</div>\n        </>\n    }\n}\n\n#[function_component]\npub fn App() -> Html {\n    html! {\n        <ReactorProvider<PrimeReactor> path=\"/worker.js\">\n            <Main />\n        </ReactorProvider<PrimeReactor>>\n    }\n}\n"
  },
  {
    "path": "examples/webgl/Cargo.toml",
    "content": "[package]\nname = \"webgl\"\nversion = \"0.1.0\"\nauthors = [\"Miklós Tusz <mdtusz@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\n\n[dependencies]\njs-sys.workspace = true\nwasm-bindgen.workspace = true\nyew = { path = \"../../packages/yew\", features = [\"csr\"] }\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n  'HtmlCanvasElement',\n  'WebGlBuffer',\n  'WebGlProgram',\n  'WebGlRenderingContext',\n  'WebGlShader',\n  'WebGlUniformLocation',\n]\n"
  },
  {
    "path": "examples/webgl/README.md",
    "content": "# WebGL Example\n\n[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fwebgl)](https://examples.yew.rs/webgl)\n\nThis is a simple demo using WebGL with Yew to initialize the GL context, create\na render loop, and draw to the canvas with basic shaders using `web-sys`.\n\n## Concepts\n\n- Accessing a DOM element using [`NodeRef`](https://yew.rs/docs/concepts/components/refs/).\n- Using Javascript APIs with `web-sys`.\n\n## Improvements\n\n- Use a much more flashy shader\n\n## Running\n\nRun this application with the trunk development server:\n\n```bash\ntrunk serve --open\n```"
  },
  {
    "path": "examples/webgl/Trunk.toml",
    "content": "[tools]\nwasm_opt = \"version_128\"\n"
  },
  {
    "path": "examples/webgl/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Yew • WebGL</title>\n\n    <link data-trunk rel=\"rust\" />\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "examples/webgl/src/basic.frag",
    "content": "precision mediump float;\n\nuniform float u_time;\n\nvoid main() {\n    float r = sin(u_time * 0.0003);\n    float g = sin(u_time * 0.0005);\n    float b = sin(u_time * 0.0007);\n\n    gl_FragColor = vec4(r, g, b, 1.0);\n}\n"
  },
  {
    "path": "examples/webgl/src/basic.vert",
    "content": "precision mediump float;\n\nattribute vec2 a_position;\n\nvoid main() {\n    gl_Position = vec4(a_position, 0.0, 1.0);\n}\n"
  },
  {
    "path": "examples/webgl/src/main.rs",
    "content": "use std::cell::RefCell;\nuse std::rc::Rc;\n\nuse wasm_bindgen::prelude::*;\nuse wasm_bindgen::JsCast;\nuse web_sys::{window, HtmlCanvasElement, WebGlRenderingContext as GL, WebGlRenderingContext};\nuse yew::{html, Component, Context, Html, NodeRef};\n\n// Wrap gl in Rc (Arc for multi-threaded) so it can be injected into the render-loop closure.\npub struct App {\n    node_ref: NodeRef,\n}\n\nimpl Component for App {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            <canvas ref={self.node_ref.clone()} />\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        // Only start the render loop if it's the first render\n        // There's no loop cancellation taking place, so if multiple renders happen,\n        // there would be multiple loops running. That doesn't *really* matter here because\n        // there's no props update and no SSR is taking place, but it is something to keep in\n        // consideration\n        if !first_render {\n            return;\n        }\n        // Once rendered, store references for the canvas and GL context. These can be used for\n        // resizing the rendering area when the window or canvas element are resized, as well as\n        // for making GL calls.\n        let canvas = self.node_ref.cast::<HtmlCanvasElement>().unwrap();\n        let gl: GL = canvas\n            .get_context(\"webgl\")\n            .unwrap()\n            .unwrap()\n            .dyn_into()\n            .unwrap();\n        Self::render_gl(gl);\n    }\n}\n\nimpl App {\n    fn request_animation_frame(f: &Closure<dyn FnMut()>) {\n        window()\n            .unwrap()\n            .request_animation_frame(f.as_ref().unchecked_ref())\n            .expect(\"should register `requestAnimationFrame` OK\");\n    }\n\n    fn render_gl(gl: WebGlRenderingContext) {\n        // This should log only once -- not once per frame\n\n        let mut timestamp = 0.0;\n\n        let vert_code = include_str!(\"./basic.vert\");\n        let frag_code = include_str!(\"./basic.frag\");\n\n        // This list of vertices will draw two triangles to cover the entire canvas.\n        let vertices: Vec<f32> = vec![\n            -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0,\n        ];\n        let vertex_buffer = gl.create_buffer().unwrap();\n        let verts = js_sys::Float32Array::from(vertices.as_slice());\n\n        gl.bind_buffer(GL::ARRAY_BUFFER, Some(&vertex_buffer));\n        gl.buffer_data_with_array_buffer_view(GL::ARRAY_BUFFER, &verts, GL::STATIC_DRAW);\n\n        let vert_shader = gl.create_shader(GL::VERTEX_SHADER).unwrap();\n        gl.shader_source(&vert_shader, vert_code);\n        gl.compile_shader(&vert_shader);\n\n        let frag_shader = gl.create_shader(GL::FRAGMENT_SHADER).unwrap();\n        gl.shader_source(&frag_shader, frag_code);\n        gl.compile_shader(&frag_shader);\n\n        let shader_program = gl.create_program().unwrap();\n        gl.attach_shader(&shader_program, &vert_shader);\n        gl.attach_shader(&shader_program, &frag_shader);\n        gl.link_program(&shader_program);\n\n        gl.use_program(Some(&shader_program));\n\n        // Attach the position vector as an attribute for the GL context.\n        let position = gl.get_attrib_location(&shader_program, \"a_position\") as u32;\n        gl.vertex_attrib_pointer_with_i32(position, 2, GL::FLOAT, false, 0, 0);\n        gl.enable_vertex_attrib_array(position);\n\n        // Attach the time as a uniform for the GL context.\n        let time = gl.get_uniform_location(&shader_program, \"u_time\");\n        gl.uniform1f(time.as_ref(), timestamp as f32);\n\n        gl.draw_arrays(GL::TRIANGLES, 0, 6);\n\n        // Gloo-render's request_animation_frame has this extra closure\n        // wrapping logic running every frame, unnecessary cost.\n        // Here constructing the wrapped closure just once.\n\n        let cb = Rc::new(RefCell::new(None));\n\n        *cb.borrow_mut() = Some(Closure::wrap(Box::new({\n            let cb = cb.clone();\n            move || {\n                // This should repeat every frame\n                timestamp += 20.0;\n                gl.uniform1f(time.as_ref(), timestamp as f32);\n                gl.draw_arrays(GL::TRIANGLES, 0, 6);\n                App::request_animation_frame(cb.borrow().as_ref().unwrap());\n            }\n        }) as Box<dyn FnMut()>));\n\n        App::request_animation_frame(cb.borrow().as_ref().unwrap());\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n"
  },
  {
    "path": "firebase.json",
    "content": "{\n  \"hosting\": [\n    {\n      \"target\": \"website\",\n      \"public\": \"website/build/\",\n      \"cleanUrls\": true,\n      \"redirects\": [],\n      \"rewrites\": [\n        {\n          \"source\": \"/api/**\",\n          \"dynamicLinks\": true\n        }\n      ]\n    },\n    {\n      \"target\": \"api\",\n      \"public\": \"api-docs/dist/\",\n      \"redirects\": [\n        {\n          \"source\": \"/\",\n          \"destination\": \"https://docs.rs/yew\",\n          \"type\": 302\n        },\n        {\n          \"regex\": \"/(yew_((agent|router)?_?(macro)?))\",\n          \"destination\": \"https://docs.rs/:1\",\n          \"type\": 302\n        }\n      ]\n    },\n    {\n      \"target\": \"examples\",\n      \"public\": \"dist\",\n      \"rewrites\": [\n        {\n          \"source\": \"/router/**\",\n          \"destination\": \"/router/index.html\"\n        },\n        {\n          \"source\": \"/todomvc/**\",\n          \"destination\": \"/todomvc/index.html\"\n        }\n      ],\n      \"redirects\": [\n        {\n          \"source\": \"/\",\n          \"destination\": \"https://yew.rs/getting-started/examples\",\n          \"type\": 302\n        }\n      ]\n    }\n  ],\n  \"headers\": [ {\n    \"source\": \"tutorial/*.json\",\n    \"headers\": [ {\n      \"key\": \"Access-Control-Allow-Origin\",\n      \"value\": \"*\"\n    } ]\n  } ],\n  \"emulators\": {\n    \"hosting\": {\n      \"port\": 5000\n    },\n    \"ui\": {\n      \"enabled\": true\n    }\n  }\n}\n"
  },
  {
    "path": "packages/yew/Cargo.toml",
    "content": "[package]\nname = \"yew\"\nversion = \"0.23.0\"\nedition = \"2021\"\nauthors = [\n  \"Denis Kolodin <deniskolodin@gmail.com>\",\n  \"Justin Starry <justin@yew.rs>\",\n]\nrepository = \"https://github.com/yewstack/yew\"\nhomepage = \"https://yew.rs\"\ndocumentation = \"https://docs.rs/yew/\"\nlicense = \"MIT OR Apache-2.0\"\nkeywords = [\"web\", \"webasm\", \"javascript\"]\ncategories = [\"gui\", \"wasm\", \"web-programming\"]\ndescription = \"A framework for creating reliable and efficient web applications\"\nreadme = \"../../README.md\"\nrust-version = \"1.84.0\"\n\n[dependencies]\nconsole_error_panic_hook = \"0.1\"\ngloo.workspace = true\nindexmap = { version = \"2.13\", features = [\"std\"] }\njs-sys.workspace = true\nslab = \"0.4\"\nwasm-bindgen.workspace = true\nyew-macro = { version = \"^0.23.0\", path = \"../yew-macro\" }\nthiserror.workspace = true\nfutures = { workspace = true, features = [\"std\"] }\nhtml-escape = { version = \"0.2.13\", optional = true }\nimplicit-clone = { workspace = true, features = [\"map\"] }\nbase64ct = { version = \"1.6.0\", features = [\"std\"], optional = true }\nbincode = { workspace = true, optional = true }\nserde = { workspace = true, features = [\"derive\"] }\ntracing = \"0.1.44\"\ntokise = \"0.2.0\"\nrustversion.workspace = true\n\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\nwasm-bindgen-futures.workspace = true\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dependencies]\n# We still need tokio as we have docs linked to it.\ntokio = { workspace = true, features = [\"rt\"] }\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n  \"AnimationEvent\",\n  \"Document\",\n  \"DragEvent\",\n  \"Element\",\n  \"ErrorEvent\",\n  \"Event\",\n  \"EventInit\",\n  \"EventTarget\",\n  \"FocusEvent\",\n  \"HtmlElement\",\n  \"HtmlInputElement\",\n  \"HtmlCollection\",\n  \"HtmlTextAreaElement\",\n  \"InputEvent\",\n  \"InputEventInit\",\n  \"KeyboardEvent\",\n  \"Location\",\n  \"MouseEvent\",\n  \"Node\",\n  \"NodeList\",\n  \"PointerEvent\",\n  \"ProgressEvent\",\n  \"ShadowRoot\",\n  \"Text\",\n  \"TouchEvent\",\n  \"TransitionEvent\",\n  \"UiEvent\",\n  \"WheelEvent\",\n  \"Window\",\n  \"HtmlScriptElement\",\n  \"SubmitEvent\",\n]\n\n[target.'cfg(not(target_arch = \"wasm32\"))'.dev-dependencies]\ntokio = { workspace = true, features = [\"rt\", \"rt-multi-thread\", \"macros\"] }\n\n[target.'cfg(all(target_arch = \"wasm32\", target_os = \"wasi\"))'.dependencies]\ntokio = { workspace = true, features = [\"macros\", \"rt\", \"time\"] }\n\n[dev-dependencies]\nwasm-bindgen-test = \"0.3\"\ngloo = { workspace = true, features = [\"futures\"] }\nwasm-bindgen-futures.workspace = true\ntrybuild = { workspace = true }\n\n[dev-dependencies.web-sys]\nworkspace = true\nfeatures = [\"ShadowRootInit\", \"ShadowRootMode\", \"HtmlButtonElement\"]\n\n[features]\nssr = [\"dep:html-escape\", \"dep:base64ct\", \"dep:bincode\"]\ncsr = []\nhydration = [\"csr\", \"dep:bincode\"]\nnot_browser_env = []\ndefault = []\ntest = []\nserde = [\"implicit-clone/serde\"]\n\n[package.metadata.docs.rs]\nall-features = true\nrustdoc-args = [\"--cfg\", \"documenting\"]\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "packages/yew/Makefile.toml",
    "content": "[tasks.native-test]\ncommand = \"cargo\"\nargs = [\"test\", \"--features\", \"csr,ssr,hydration,test\"]\n\n[tasks.wasm-test]\ncommand = \"wasm-pack\"\nargs = [\n    \"test\",\n    \"--firefox\",\n    \"--headless\",\n    \"--\",\n    \"--features\",\n    \"csr,hydration,ssr,test\",\n]\n\n[tasks.ssr-test]\ncommand = \"cargo\"\nargs = [\"test\", \"ssr_tests\", \"--features\", \"ssr\"]\n\n[tasks.test]\nargs = [\"test\", \"--all-targets\", \"--all-features\"]\ndependencies = [\"native-test\", \"wasm-test\"]\n\n[tasks.clippy-feature-soundness]\ncommand = \"cargo\"\nargs = [\n    \"hack\", \"clippy\",\n    \"-p\", \"yew\", \"-p\", \"yew-agent\", \"-p\", \"yew-router\",\n    \"--feature-powerset\", \"--no-dev-deps\",\n    \"--keep-going\",\n    \"--\", \"-D\", \"warnings\",\n]\n"
  },
  {
    "path": "packages/yew/src/app_handle.rs",
    "content": "//! [AppHandle] contains the state Yew keeps to bootstrap a component in an isolated scope.\n\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse web_sys::Element;\n\nuse crate::dom_bundle::{BSubtree, DomSlot};\nuse crate::html::{BaseComponent, Scope, Scoped};\n\n/// An instance of an application.\n#[derive(Debug)]\npub struct AppHandle<COMP: BaseComponent> {\n    /// `Scope` holder\n    pub(crate) scope: Scope<COMP>,\n}\n\nimpl<COMP> AppHandle<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    /// The main entry point of a Yew program which also allows passing properties. It works\n    /// similarly to the `program` function in Elm. You should provide an initial model, `update`\n    /// function which will update the state of the model and a `view` function which\n    /// will render the model to a virtual DOM tree.\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        name = \"mount\",\n        skip(props),\n    )]\n    pub(crate) fn mount_with_props(host: Element, props: Rc<COMP::Properties>) -> Self {\n        clear_element(&host);\n        let app = Self {\n            scope: Scope::new(None),\n        };\n        let hosting_root = BSubtree::create_root(&host);\n        let _ = app\n            .scope\n            .mount_in_place(hosting_root, host, DomSlot::at_end(), props);\n\n        app\n    }\n\n    /// Update the properties of the app's root component.\n    ///\n    /// This can be an alternative to sending and handling messages. The existing component will be\n    /// reused and have its properties updates. This will presumably trigger a re-render, refer to\n    /// the [`changed`] lifecycle for details.\n    ///\n    /// [`changed`]: crate::Component::changed\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        skip_all,\n    )]\n    pub fn update(&mut self, new_props: COMP::Properties) {\n        self.scope.reuse(Rc::new(new_props), DomSlot::at_end())\n    }\n\n    /// Schedule the app for destruction\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        skip_all,\n    )]\n    pub fn destroy(self) {\n        self.scope.destroy(false)\n    }\n}\n\nimpl<COMP> Deref for AppHandle<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    type Target = Scope<COMP>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.scope\n    }\n}\n\n/// Removes anything from the given element.\nfn clear_element(host: &Element) {\n    while let Some(child) = host.last_child() {\n        host.remove_child(&child).expect(\"can't remove a child\");\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::Fragment;\n\n    impl<COMP> AppHandle<COMP>\n    where\n        COMP: BaseComponent,\n    {\n        #[tracing::instrument(\n            level = tracing::Level::DEBUG,\n            name = \"hydrate\",\n            skip(props),\n        )]\n        pub(crate) fn hydrate_with_props(host: Element, props: Rc<COMP::Properties>) -> Self {\n            let app = Self {\n                scope: Scope::new(None),\n            };\n\n            let mut fragment = Fragment::collect_children(&host);\n            let hosting_root = BSubtree::create_root(&host);\n\n            let mut previous_next_sibling = None;\n            app.scope.hydrate_in_place(\n                hosting_root,\n                host.clone(),\n                &mut fragment,\n                Rc::clone(&props),\n                &mut previous_next_sibling,\n            );\n            if let Some(previous_next_sibling) = previous_next_sibling {\n                previous_next_sibling.reassign(DomSlot::at_end());\n            }\n\n            // We remove all remaining nodes, this mimics the clear_element behaviour in\n            // mount_with_props.\n            for node in fragment.iter() {\n                host.remove_child(node).unwrap();\n            }\n\n            app\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/callback.rs",
    "content": "//! This module contains data types for interacting with `Scope`s.\n//!\n//! ## Relevant examples\n//! - [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n//! - [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n\nuse std::fmt;\nuse std::rc::Rc;\n\nuse crate::html::ImplicitClone;\n\nmacro_rules! generate_callback_impls {\n    ($callback:ident, $in_ty:ty, $out_var:ident => $out_val:expr) => {\n        impl<IN, OUT, F: Fn($in_ty) -> OUT + 'static> From<F> for $callback<IN, OUT> {\n            fn from(func: F) -> Self {\n                $callback { cb: Rc::new(func) }\n            }\n        }\n\n        impl<IN, OUT> Clone for $callback<IN, OUT> {\n            fn clone(&self) -> Self {\n                Self {\n                    cb: self.cb.clone(),\n                }\n            }\n        }\n\n        // We are okay with comparisons from different compilation units to result in false\n        // not-equal results. This should only lead in the worst-case to some unneeded re-renders.\n        #[allow(ambiguous_wide_pointer_comparisons)]\n        impl<IN, OUT> PartialEq for $callback<IN, OUT> {\n            fn eq(&self, other: &$callback<IN, OUT>) -> bool {\n                let ($callback { cb }, $callback { cb: rhs_cb }) = (self, other);\n                Rc::ptr_eq(cb, rhs_cb)\n            }\n        }\n\n        impl<IN, OUT> fmt::Debug for $callback<IN, OUT> {\n            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n                write!(f, \"$callback<_>\")\n            }\n        }\n\n        impl<IN, OUT> $callback<IN, OUT> {\n            /// This method calls the callback's function.\n            pub fn emit(&self, value: $in_ty) -> OUT {\n                (*self.cb)(value)\n            }\n        }\n\n        impl<IN> $callback<IN> {\n            /// Creates a \"no-op\" callback which can be used when it is not suitable to use an\n            /// `Option<$callback>`.\n            pub fn noop() -> Self {\n                Self::from(|_: $in_ty| ())\n            }\n        }\n\n        impl<IN> Default for $callback<IN> {\n            fn default() -> Self {\n                Self::noop()\n            }\n        }\n\n        impl<IN: 'static, OUT: 'static> $callback<IN, OUT> {\n            /// Creates a new [`Callback`] from another callback and a function.\n            ///\n            /// That when emitted will call that function and will emit the original callback\n            pub fn reform<F, T>(&self, func: F) -> Callback<T, OUT>\n            where\n                F: Fn(T) -> IN + 'static,\n            {\n                let this = self.clone();\n                let func = move |input: T| {\n                    #[allow(unused_mut)]\n                    let mut $out_var = func(input);\n                    this.emit($out_val)\n                };\n                func.into()\n            }\n\n            /// Creates a new [`CallbackRef`] from another callback and a function.\n            ///\n            /// That when emitted will call that function and will emit the original callback\n            pub fn reform_ref<F, T>(&self, func: F) -> CallbackRef<T, OUT>\n            where\n                F: Fn(&T) -> $in_ty + 'static,\n            {\n                let this = self.clone();\n                let func = move |input: &T| {\n                    #[allow(unused_mut)]\n                    let mut $out_var = func(input);\n                    this.emit($out_val)\n                };\n                func.into()\n            }\n\n            /// Creates a new [`CallbackRefMut`] from another callback and a function.\n            ///\n            /// That when emitted will call that function and will emit the original callback\n            pub fn reform_ref_mut<F, T>(&self, func: F) -> CallbackRefMut<T, OUT>\n            where\n                F: Fn(&mut T) -> $in_ty + 'static,\n            {\n                let this = self.clone();\n                let func = move |input: &mut T| {\n                    #[allow(unused_mut)]\n                    let mut $out_var = func(input);\n                    this.emit($out_val)\n                };\n                func.into()\n            }\n\n            /// Creates a new [`Callback`] from another callback and a function.\n            ///\n            /// When emitted will call the function and, only if it returns `Some(value)`, will emit\n            /// `value` to the original callback.\n            pub fn filter_reform<F, T>(&self, func: F) -> Callback<T, Option<OUT>>\n            where\n                F: Fn(T) -> Option<IN> + 'static,\n            {\n                let this = self.clone();\n                let func = move |input: T| {\n                    func(input).map(\n                        #[allow(unused_mut)]\n                        |mut $out_var| this.emit($out_val),\n                    )\n                };\n                func.into()\n            }\n\n            /// Creates a new [`CallbackRef`] from another callback and a function.\n            ///\n            /// When emitted will call the function and, only if it returns `Some(value)`, will emit\n            /// `value` to the original callback.\n            pub fn filter_reform_ref<F, T>(&self, func: F) -> CallbackRef<T, Option<OUT>>\n            where\n                F: Fn(&T) -> Option<$in_ty> + 'static,\n            {\n                let this = self.clone();\n                let func = move |input: &T| {\n                    func(input).map(\n                        #[allow(unused_mut)]\n                        |mut $out_var| this.emit($out_val),\n                    )\n                };\n                func.into()\n            }\n\n            /// Creates a new [`CallbackRefMut`] from another callback and a function.\n            ///\n            /// When emitted will call the function and, only if it returns `Some(value)`, will emit\n            /// `value` to the original callback.\n            pub fn filter_reform_ref_mut<F, T>(&self, func: F) -> CallbackRefMut<T, Option<OUT>>\n            where\n                F: Fn(&mut T) -> Option<$in_ty> + 'static,\n            {\n                let this = self.clone();\n                let func = move |input: &mut T| {\n                    func(input).map(\n                        #[allow(unused_mut)]\n                        |mut $out_var| this.emit($out_val),\n                    )\n                };\n                func.into()\n            }\n        }\n\n        impl<IN, OUT> ImplicitClone for $callback<IN, OUT> {}\n    };\n}\n\n/// Universal callback wrapper.\n///\n/// An `Rc` wrapper is used to make it cloneable.\npub struct Callback<IN, OUT = ()> {\n    /// A callback which can be called multiple times\n    pub(crate) cb: Rc<dyn Fn(IN) -> OUT>,\n}\n\ngenerate_callback_impls!(Callback, IN, output => output);\n\n/// Universal callback wrapper with reference in argument.\n///\n/// An `Rc` wrapper is used to make it cloneable.\npub struct CallbackRef<IN, OUT = ()> {\n    /// A callback which can be called multiple times\n    pub(crate) cb: Rc<dyn Fn(&IN) -> OUT>,\n}\n\ngenerate_callback_impls!(CallbackRef, &IN, output => #[allow(clippy::needless_borrow)] &output);\n\n/// Universal callback wrapper with mutable reference in argument.\n///\n/// An `Rc` wrapper is used to make it cloneable.\npub struct CallbackRefMut<IN, OUT = ()> {\n    /// A callback which can be called multiple times\n    pub(crate) cb: Rc<dyn Fn(&mut IN) -> OUT>,\n}\n\ngenerate_callback_impls!(CallbackRefMut, &mut IN, output => &mut output);\n\n#[cfg(test)]\nmod test {\n    use std::sync::Mutex;\n\n    use super::*;\n\n    /// emit the callback with the provided value\n    fn emit<T, I, R: 'static + Clone, F, OUT>(values: I, f: F) -> Vec<R>\n    where\n        I: IntoIterator<Item = T>,\n        F: FnOnce(Callback<R, ()>) -> Callback<T, OUT>,\n    {\n        let result = Rc::new(Mutex::new(Vec::new()));\n        let cb_result = result.clone();\n        let cb = f(Callback::<R, ()>::from(move |v| {\n            cb_result.lock().unwrap().push(v);\n        }));\n        for value in values {\n            cb.emit(value);\n        }\n        let x = result.lock().unwrap().clone();\n        x\n    }\n\n    #[test]\n    fn test_callback() {\n        assert_eq!(*emit([true, false], |cb| cb), vec![true, false]);\n    }\n\n    #[test]\n    fn test_reform() {\n        assert_eq!(\n            *emit([true, false], |cb| cb.reform(|v: bool| !v)),\n            vec![false, true]\n        );\n    }\n\n    #[test]\n    fn test_filter_reform() {\n        assert_eq!(\n            *emit([1, 2, 3], |cb| cb.filter_reform(|v| match v {\n                1 => Some(true),\n                2 => Some(false),\n                _ => None,\n            })),\n            vec![true, false]\n        );\n    }\n\n    #[test]\n    fn test_ref() {\n        let callback: CallbackRef<usize, usize> = CallbackRef::from(|x: &usize| *x);\n        assert_eq!(callback.emit(&42), 42);\n    }\n\n    #[test]\n    fn test_ref_mut() {\n        let callback: CallbackRefMut<usize, ()> = CallbackRefMut::from(|x: &mut usize| *x = 42);\n        let mut value: usize = 0;\n        callback.emit(&mut value);\n        assert_eq!(value, 42);\n    }\n\n    #[test]\n    fn test_reform_ref() {\n        let callback: Callback<usize, usize> = Callback::from(|x: usize| x + 1);\n        let reformed: CallbackRef<usize, usize> = callback.reform_ref(|x: &usize| *x + 2);\n        assert_eq!(reformed.emit(&42), 45);\n    }\n\n    #[test]\n    fn test_reform_ref_mut() {\n        let callback: CallbackRefMut<usize, ()> = CallbackRefMut::from(|x: &mut usize| *x += 1);\n        let reformed: CallbackRefMut<usize, ()> = callback.reform_ref_mut(|x: &mut usize| {\n            *x += 2;\n            x\n        });\n        let mut value: usize = 42;\n        reformed.emit(&mut value);\n        assert_eq!(value, 45);\n    }\n\n    #[test]\n    fn test_filter_reform_ref() {\n        let callback: Callback<usize, usize> = Callback::from(|x: usize| x + 1);\n        let reformed: CallbackRef<usize, Option<usize>> =\n            callback.filter_reform_ref(|x: &usize| Some(*x + 2));\n        assert_eq!(reformed.emit(&42), Some(45));\n    }\n\n    #[test]\n    fn test_filter_reform_ref_mut() {\n        let callback: CallbackRefMut<usize, ()> = CallbackRefMut::from(|x: &mut usize| *x += 1);\n        let reformed: CallbackRefMut<usize, Option<()>> =\n            callback.filter_reform_ref_mut(|x: &mut usize| {\n                *x += 2;\n                Some(x)\n            });\n        let mut value: usize = 42;\n        reformed.emit(&mut value).expect(\"is some\");\n        assert_eq!(value, 45);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/context.rs",
    "content": "//! This module defines the `ContextProvider` component.\n\nuse std::cell::RefCell;\n\nuse slab::Slab;\n\nuse crate::html::Scope;\nuse crate::{Callback, Component, Context, Html, Properties};\n\n/// Props for [`ContextProvider`]\n#[derive(Debug, Clone, PartialEq, Properties)]\npub struct ContextProviderProps<T: Clone + PartialEq> {\n    /// Context value to be passed down\n    pub context: T,\n    /// Children\n    pub children: Html,\n}\n\n/// The context provider component.\n///\n/// Every child (direct or indirect) of this component may access the context value.\n/// In order to consume contexts, [`Scope::context`][Scope::context] method is used,\n/// In function components the `use_context` hook is used.\n#[derive(Debug)]\npub struct ContextProvider<T: Clone + PartialEq + 'static> {\n    context: T,\n    consumers: RefCell<Slab<Callback<T>>>,\n}\n\n/// Owns the connection to a context provider. When dropped, the component will\n/// no longer receive updates from the provider.\n#[derive(Debug)]\npub struct ContextHandle<T: Clone + PartialEq + 'static> {\n    provider: Scope<ContextProvider<T>>,\n    key: usize,\n}\n\nimpl<T: Clone + PartialEq + 'static> Drop for ContextHandle<T> {\n    fn drop(&mut self) {\n        if let Some(component) = self.provider.get_component() {\n            component.consumers.borrow_mut().remove(self.key);\n        }\n    }\n}\n\nimpl<T: Clone + PartialEq> ContextProvider<T> {\n    /// Add the callback to the subscriber list to be called whenever the context changes.\n    /// The consumer is unsubscribed as soon as the callback is dropped.\n    pub(crate) fn subscribe_consumer(\n        &self,\n        callback: Callback<T>,\n        scope: Scope<Self>,\n    ) -> (T, ContextHandle<T>) {\n        let ctx = self.context.clone();\n        let key = self.consumers.borrow_mut().insert(callback);\n\n        (\n            ctx,\n            ContextHandle {\n                provider: scope,\n                key,\n            },\n        )\n    }\n\n    /// Notify all subscribed consumers and remove dropped consumers from the list.\n    fn notify_consumers(&mut self) {\n        let consumers: Vec<Callback<T>> = self\n            .consumers\n            .borrow()\n            .iter()\n            .map(|(_, v)| v.clone())\n            .collect();\n        for consumer in consumers {\n            consumer.emit(self.context.clone());\n        }\n    }\n}\n\nimpl<T: Clone + PartialEq + 'static> Component for ContextProvider<T> {\n    type Message = ();\n    type Properties = ContextProviderProps<T>;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let props = ctx.props();\n        Self {\n            context: props.context.clone(),\n            consumers: RefCell::new(Slab::new()),\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {\n        let props = ctx.props();\n\n        let should_render = old_props.children != props.children;\n\n        if self.context != props.context {\n            self.context = props.context.clone();\n            self.notify_consumers();\n        }\n\n        should_render\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        ctx.props().children.clone()\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/bcomp.rs",
    "content": "//! This module contains the bundle implementation of a virtual component [BComp].\n\nuse std::any::TypeId;\nuse std::borrow::Borrow;\nuse std::fmt;\n\nuse web_sys::Element;\n\nuse super::{BNode, BSubtree, DomSlot, DynamicDomSlot, Reconcilable, ReconcileTarget};\nuse crate::html::{AnyScope, Scoped};\nuse crate::virtual_dom::{Key, VComp};\n\n/// A virtual component. Compare with [VComp].\npub(super) struct BComp {\n    type_id: TypeId,\n    scope: Box<dyn Scoped>,\n    /// An internal [`DomSlot`] passed around to track this components position. This\n    /// will dynamically adjust when a lifecycle changes the render state of this component.\n    own_position: DynamicDomSlot,\n    key: Option<Key>,\n}\n\nimpl BComp {\n    /// Get the key of the underlying component\n    pub fn key(&self) -> Option<&Key> {\n        self.key.as_ref()\n    }\n}\n\nimpl fmt::Debug for BComp {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"BComp\")\n            .field(\"root\", &self.scope.as_ref().render_state())\n            .finish()\n    }\n}\n\nimpl ReconcileTarget for BComp {\n    fn detach(self, _root: &BSubtree, _parent: &Element, parent_to_detach: bool) {\n        self.scope.destroy_boxed(parent_to_detach);\n    }\n\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        self.scope.shift_node(next_parent.clone(), slot);\n\n        self.own_position.to_position()\n    }\n}\n\nimpl Reconcilable for VComp {\n    type Bundle = BComp;\n\n    fn attach(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let VComp {\n            type_id,\n            mountable,\n            key,\n            ..\n        } = self;\n\n        let (scope, internal_ref) = mountable.mount(root, parent_scope, parent.to_owned(), slot);\n\n        (\n            internal_ref.to_position(),\n            BComp {\n                type_id,\n                scope,\n                own_position: internal_ref,\n                key,\n            },\n        )\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        match bundle {\n            // If the existing bundle is the same type, reuse it and update its properties\n            BNode::Comp(ref mut bcomp)\n                if self.type_id == bcomp.type_id && self.key == bcomp.key =>\n            {\n                self.reconcile(root, parent_scope, parent, slot, bcomp)\n            }\n            _ => self.replace(root, parent_scope, parent, slot, bundle),\n        }\n    }\n\n    fn reconcile(\n        self,\n        _root: &BSubtree,\n        _parent_scope: &AnyScope,\n        _parent: &Element,\n        slot: DomSlot,\n        bcomp: &mut Self::Bundle,\n    ) -> DomSlot {\n        let VComp { mountable, key, .. } = self;\n\n        bcomp.key = key;\n        mountable.reuse(bcomp.scope.borrow(), slot);\n        bcomp.own_position.to_position()\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::{Fragment, Hydratable};\n\n    impl Hydratable for VComp {\n        fn hydrate(\n            self,\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            let VComp {\n                type_id,\n                mountable,\n                key,\n                ..\n            } = self;\n\n            let (scope, own_slot) = mountable.hydrate(\n                root.clone(),\n                parent_scope,\n                parent.clone(),\n                fragment,\n                prev_next_sibling,\n            );\n\n            BComp {\n                type_id,\n                scope,\n                own_position: own_slot,\n                key,\n            }\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod tests {\n    use gloo::utils::document;\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n    use web_sys::Element;\n\n    use super::*;\n    use crate::dom_bundle::Reconcilable;\n    use crate::virtual_dom::{Key, VChild, VNode};\n    use crate::{html, scheduler, Children, Component, Context, Html, Properties};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    struct Comp;\n\n    #[derive(Clone, PartialEq, Properties)]\n    struct Props {\n        #[prop_or_default]\n        field_1: u32,\n        #[prop_or_default]\n        field_2: u32,\n    }\n\n    impl Component for Comp {\n        type Message = ();\n        type Properties = Props;\n\n        fn create(_: &Context<Self>) -> Self {\n            Comp\n        }\n\n        fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n            unimplemented!();\n        }\n\n        fn view(&self, _ctx: &Context<Self>) -> Html {\n            html! { <div/> }\n        }\n    }\n\n    #[test]\n    fn update_loop() {\n        let (root, scope, parent) = setup_parent();\n\n        let comp = html! { <Comp></Comp> };\n        let (_, mut bundle) = comp.attach(&root, &scope, &parent, DomSlot::at_end());\n        scheduler::start_now();\n\n        for _ in 0..10000 {\n            let node = html! { <Comp></Comp> };\n            node.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut bundle);\n            scheduler::start_now();\n        }\n    }\n\n    #[test]\n    fn set_properties_to_component() {\n        html! {\n            <Comp />\n        };\n\n        html! {\n            <Comp field_1=1 />\n        };\n\n        html! {\n            <Comp field_2=2 />\n        };\n\n        html! {\n            <Comp field_1=1 field_2=2 />\n        };\n\n        let props = Props {\n            field_1: 1,\n            field_2: 1,\n        };\n\n        html! {\n            <Comp ..props />\n        };\n    }\n\n    #[test]\n    fn set_component_key() {\n        let test_key: Key = \"test\".to_string().into();\n        let check_key = |vnode: VNode| {\n            assert_eq!(vnode.key(), Some(&test_key));\n        };\n\n        let props = Props {\n            field_1: 1,\n            field_2: 1,\n        };\n        let props_2 = props.clone();\n\n        check_key(html! { <Comp key={test_key.clone()} /> });\n        check_key(html! { <Comp key={test_key.clone()} field_1=1 /> });\n        check_key(html! { <Comp field_1=1 key={test_key.clone()} /> });\n        check_key(html! { <Comp key={test_key.clone()} ..props /> });\n        check_key(html! { <Comp key={test_key.clone()} ..props_2 /> });\n    }\n\n    #[test]\n    fn vchild_partialeq() {\n        let vchild1: VChild<Comp> = VChild::new(\n            Props {\n                field_1: 1,\n                field_2: 1,\n            },\n            None,\n        );\n\n        let vchild2: VChild<Comp> = VChild::new(\n            Props {\n                field_1: 1,\n                field_2: 1,\n            },\n            None,\n        );\n\n        let vchild3: VChild<Comp> = VChild::new(\n            Props {\n                field_1: 2,\n                field_2: 2,\n            },\n            None,\n        );\n\n        assert_eq!(vchild1, vchild2);\n        assert_ne!(vchild1, vchild3);\n        assert_ne!(vchild2, vchild3);\n    }\n\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct ListProps {\n        pub children: Children,\n    }\n    pub struct List;\n    impl Component for List {\n        type Message = ();\n        type Properties = ListProps;\n\n        fn create(_: &Context<Self>) -> Self {\n            Self\n        }\n\n        fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n            unimplemented!();\n        }\n\n        fn changed(&mut self, _ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n            unimplemented!();\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> Html {\n            let item_iter = ctx\n                .props()\n                .children\n                .iter()\n                .map(|item| html! {<li>{ item }</li>});\n            html! {\n                <ul>{ for item_iter }</ul>\n            }\n        }\n    }\n\n    fn setup_parent() -> (BSubtree, AnyScope, Element) {\n        let scope = AnyScope::test();\n        let parent = document().create_element(\"div\").unwrap();\n        let root = BSubtree::create_root(&parent);\n\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        (root, scope, parent)\n    }\n\n    fn get_html(node: Html, root: &BSubtree, scope: &AnyScope, parent: &Element) -> String {\n        // clear parent\n        parent.set_inner_html(\"\");\n\n        node.attach(root, scope, parent, DomSlot::at_end());\n        scheduler::start_now();\n        parent.inner_html()\n    }\n\n    #[test]\n    fn all_ways_of_passing_children_work() {\n        let (root, scope, parent) = setup_parent();\n\n        let children: Vec<_> = vec![\"a\", \"b\", \"c\"]\n            .drain(..)\n            .map(|text| html! {<span>{ text }</span>})\n            .collect();\n        let children_renderer = Children::new(children.clone());\n        let expected_html = \"\\\n        <ul><li><span>a</span></li><li><span>b</span></li><li><span>c</span></li></ul>\";\n\n        let prop_method = html! {\n            <List children={children_renderer.clone()} />\n        };\n        assert_eq!(get_html(prop_method, &root, &scope, &parent), expected_html);\n\n        let children_renderer_method = html! {\n            <List>\n                { children_renderer }\n            </List>\n        };\n        assert_eq!(\n            get_html(children_renderer_method, &root, &scope, &parent),\n            expected_html\n        );\n\n        let direct_method = html! {\n            <List>\n                { children.clone() }\n            </List>\n        };\n        assert_eq!(\n            get_html(direct_method, &root, &scope, &parent),\n            expected_html\n        );\n\n        let for_method = html! {\n            <List>\n                { for children }\n            </List>\n        };\n        assert_eq!(get_html(for_method, &root, &scope, &parent), expected_html);\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    extern crate self as yew;\n\n    use std::marker::PhantomData;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n    use crate::{html, Children, Component, Context, Html, Properties};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    struct Comp<T> {\n        _marker: PhantomData<T>,\n    }\n\n    #[derive(Properties, Clone, PartialEq)]\n    struct CompProps {\n        #[prop_or_default]\n        children: Children,\n    }\n\n    impl<T: 'static> Component for Comp<T> {\n        type Message = ();\n        type Properties = CompProps;\n\n        fn create(_: &Context<Self>) -> Self {\n            Comp {\n                _marker: PhantomData::default(),\n            }\n        }\n\n        fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n            unimplemented!();\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> Html {\n            html! {\n                <>{ ctx.props().children.clone() }</>\n            }\n        }\n    }\n\n    struct A;\n    struct B;\n\n    #[test]\n    fn diff() {\n        let layout1 = TestLayout {\n            name: \"1\",\n            node: html! {\n                <Comp<A>>\n                    <Comp<B>></Comp<B>>\n                    {\"C\"}\n                </Comp<A>>\n            },\n            expected: \"C\",\n        };\n\n        let layout2 = TestLayout {\n            name: \"2\",\n            node: html! {\n                <Comp<A>>\n                    {\"A\"}\n                </Comp<A>>\n            },\n            expected: \"A\",\n        };\n\n        let layout3 = TestLayout {\n            name: \"3\",\n            node: html! {\n                <Comp<B>>\n                    <Comp<A>></Comp<A>>\n                    {\"B\"}\n                </Comp<B>>\n            },\n            expected: \"B\",\n        };\n\n        let layout4 = TestLayout {\n            name: \"4\",\n            node: html! {\n                <Comp<B>>\n                    <Comp<A>>{\"A\"}</Comp<A>>\n                    {\"B\"}\n                </Comp<B>>\n            },\n            expected: \"AB\",\n        };\n\n        let layout5 = TestLayout {\n            name: \"5\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <Comp<A>>\n                            {\"A\"}\n                        </Comp<A>>\n                    </>\n                    {\"B\"}\n                </Comp<B>>\n            },\n            expected: \"AB\",\n        };\n\n        let layout6 = TestLayout {\n            name: \"6\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <Comp<A>>\n                            {\"A\"}\n                        </Comp<A>>\n                        {\"B\"}\n                    </>\n                    {\"C\"}\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        let layout7 = TestLayout {\n            name: \"7\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <Comp<A>>\n                            {\"A\"}\n                        </Comp<A>>\n                        <Comp<A>>\n                            {\"B\"}\n                        </Comp<A>>\n                    </>\n                    {\"C\"}\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        let layout8 = TestLayout {\n            name: \"8\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <Comp<A>>\n                            {\"A\"}\n                        </Comp<A>>\n                        <Comp<A>>\n                            <Comp<A>>\n                                {\"B\"}\n                            </Comp<A>>\n                        </Comp<A>>\n                    </>\n                    {\"C\"}\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        let layout9 = TestLayout {\n            name: \"9\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <>\n                            {\"A\"}\n                        </>\n                        <Comp<A>>\n                            <Comp<A>>\n                                {\"B\"}\n                            </Comp<A>>\n                        </Comp<A>>\n                    </>\n                    {\"C\"}\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        let layout10 = TestLayout {\n            name: \"10\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <Comp<A>>\n                            <Comp<A>>\n                                {\"A\"}\n                            </Comp<A>>\n                        </Comp<A>>\n                        <>\n                            {\"B\"}\n                        </>\n                    </>\n                    {\"C\"}\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        let layout11 = TestLayout {\n            name: \"11\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <>\n                            <Comp<A>>\n                                <Comp<A>>\n                                    {\"A\"}\n                                </Comp<A>>\n                                {\"B\"}\n                            </Comp<A>>\n                        </>\n                    </>\n                    {\"C\"}\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        let layout12 = TestLayout {\n            name: \"12\",\n            node: html! {\n                <Comp<B>>\n                    <>\n                        <Comp<A>></Comp<A>>\n                        <>\n                            <Comp<A>>\n                                <>\n                                    <Comp<A>>\n                                        {\"A\"}\n                                    </Comp<A>>\n                                    <></>\n                                    <Comp<A>>\n                                        <Comp<A>></Comp<A>>\n                                        <></>\n                                        {\"B\"}\n                                        <></>\n                                        <Comp<A>></Comp<A>>\n                                    </Comp<A>>\n                                </>\n                            </Comp<A>>\n                            <></>\n                        </>\n                        <Comp<A>></Comp<A>>\n                    </>\n                    {\"C\"}\n                    <Comp<A>></Comp<A>>\n                    <></>\n                </Comp<B>>\n            },\n            expected: \"ABC\",\n        };\n\n        diff_layouts(vec![\n            layout1, layout2, layout3, layout4, layout5, layout6, layout7, layout8, layout9,\n            layout10, layout11, layout12,\n        ]);\n    }\n\n    #[test]\n    fn component_with_children() {\n        #[derive(Properties, PartialEq)]\n        struct Props {\n            children: Children,\n        }\n\n        struct ComponentWithChildren;\n\n        impl Component for ComponentWithChildren {\n            type Message = ();\n            type Properties = Props;\n\n            fn create(_ctx: &Context<Self>) -> Self {\n                Self\n            }\n\n            fn view(&self, ctx: &Context<Self>) -> Html {\n                html! {\n                  <ul>\n                    { for ctx.props().children.iter().map(|child| html! { <li>{ child }</li> }) }\n                  </ul>\n                }\n            }\n        }\n\n        let layout = TestLayout {\n            name: \"13\",\n            node: html! {\n                <ComponentWithChildren>\n                    if true {\n                        <span>{ \"hello\" }</span>\n                        <span>{ \"world\" }</span>\n                    }  else {\n                        <span>{ \"goodbye\" }</span>\n                        <span>{ \"world\" }</span>\n                    }\n                </ComponentWithChildren>\n            },\n            expected: \"<ul><li><span>hello</span><span>world</span></li></ul>\",\n        };\n\n        diff_layouts(vec![layout]);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/blist.rs",
    "content": "//! This module contains fragments bundles, a [BList]\nuse std::borrow::Borrow;\nuse std::cmp::Ordering;\nuse std::collections::HashSet;\nuse std::hash::Hash;\nuse std::ops::Deref;\n\nuse web_sys::Element;\n\nuse super::{test_log, BNode, BSubtree, DomSlot};\nuse crate::dom_bundle::{Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\nuse crate::utils::RcExt;\nuse crate::virtual_dom::{Key, VList, VNode};\n\n/// This struct represents a mounted [VList]\n#[derive(Debug)]\npub(super) struct BList {\n    /// The reverse (render order) list of child [BNode]s\n    rev_children: Vec<BNode>,\n    /// All [BNode]s in the BList have keys\n    fully_keyed: bool,\n    key: Option<Key>,\n}\n\nimpl VList {\n    // Splits a VList for creating / reconciling to a BList.\n    fn split_for_blist(self) -> (Option<Key>, bool, Vec<VNode>) {\n        let fully_keyed = self.fully_keyed();\n\n        let children = self\n            .children\n            .map(RcExt::unwrap_or_clone)\n            .unwrap_or_default();\n\n        (self.key, fully_keyed, children)\n    }\n}\n\nimpl Deref for BList {\n    type Target = Vec<BNode>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.rev_children\n    }\n}\n\n/// Helper struct, that keeps the position where the next element is to be placed at\n#[derive(Clone)]\nstruct NodeWriter<'s> {\n    root: &'s BSubtree,\n    parent_scope: &'s AnyScope,\n    parent: &'s Element,\n    slot: DomSlot,\n}\n\nimpl NodeWriter<'_> {\n    /// Write a new node that has no ancestor\n    fn add(self, node: VNode) -> (Self, BNode) {\n        test_log!(\"adding: {:?}\", node);\n        test_log!(\n            \"  parent={:?}, slot={:?}\",\n            self.parent.outer_html(),\n            self.slot\n        );\n        let (next, bundle) = node.attach(self.root, self.parent_scope, self.parent, self.slot);\n        test_log!(\"  next_slot: {:?}\", next);\n        (Self { slot: next, ..self }, bundle)\n    }\n\n    /// Shift a bundle into place without patching it\n    fn shift(&self, bundle: &BNode) {\n        bundle.shift(self.parent, self.slot.clone());\n    }\n\n    /// Patch a bundle with a new node\n    fn patch(self, node: VNode, bundle: &mut BNode) -> Self {\n        test_log!(\"patching: {:?} -> {:?}\", bundle, node);\n        test_log!(\n            \"  parent={:?}, slot={:?}\",\n            self.parent.outer_html(),\n            self.slot\n        );\n        // Advance the next sibling reference (from right to left)\n        let next =\n            node.reconcile_node(self.root, self.parent_scope, self.parent, self.slot, bundle);\n        test_log!(\"  next_position: {:?}\", next);\n        Self { slot: next, ..self }\n    }\n}\n/// Helper struct implementing [Eq] and [Hash] by only looking at a node's key\nstruct KeyedEntry(usize, BNode);\nimpl Borrow<Key> for KeyedEntry {\n    fn borrow(&self) -> &Key {\n        self.1.key().expect(\"unkeyed child in fully keyed list\")\n    }\n}\nimpl Hash for KeyedEntry {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        <Self as Borrow<Key>>::borrow(self).hash(state)\n    }\n}\nimpl PartialEq for KeyedEntry {\n    fn eq(&self, other: &Self) -> bool {\n        <Self as Borrow<Key>>::borrow(self) == <Self as Borrow<Key>>::borrow(other)\n    }\n}\nimpl Eq for KeyedEntry {}\n\nimpl BNode {\n    /// Assert that a bundle node is a list, or convert it to a list with a single child\n    fn make_list(&mut self) -> &mut BList {\n        match self {\n            Self::List(blist) => blist,\n            self_ => {\n                let b = std::mem::replace(self_, BNode::List(BList::new()));\n                let self_list = match self_ {\n                    BNode::List(blist) => blist,\n                    _ => unreachable!(\"just been set to the variant\"),\n                };\n                let key = b.key().cloned();\n                self_list.rev_children.push(b);\n                self_list.fully_keyed = key.is_some();\n                self_list.key = key;\n                self_list\n            }\n        }\n    }\n}\n\nimpl BList {\n    /// Create a new empty [BList]\n    pub const fn new() -> BList {\n        BList {\n            rev_children: vec![],\n            fully_keyed: true,\n            key: None,\n        }\n    }\n\n    /// Get the key of the underlying fragment\n    pub fn key(&self) -> Option<&Key> {\n        self.key.as_ref()\n    }\n\n    /// Diff and patch unkeyed child lists\n    fn apply_unkeyed(\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        lefts: Vec<VNode>,\n        rights: &mut Vec<BNode>,\n    ) -> DomSlot {\n        let mut writer = NodeWriter {\n            root,\n            parent_scope,\n            parent,\n            slot,\n        };\n\n        // Remove extra nodes\n        if lefts.len() < rights.len() {\n            for r in rights.drain(lefts.len()..) {\n                test_log!(\"removing: {:?}\", r);\n                r.detach(root, parent, false);\n            }\n        }\n\n        let mut lefts_it = lefts.into_iter().rev();\n        for (r, l) in rights.iter_mut().zip(&mut lefts_it) {\n            writer = writer.patch(l, r);\n        }\n\n        // Add missing nodes\n        for l in lefts_it {\n            let (next_writer, el) = writer.add(l);\n            rights.push(el);\n            writer = next_writer;\n        }\n        writer.slot\n    }\n\n    /// Diff and patch fully keyed child lists.\n    ///\n    /// Optimized for node addition or removal from either end of the list and small changes in the\n    /// middle.\n    fn apply_keyed(\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        left_vdoms: Vec<VNode>,\n        rev_bundles: &mut Vec<BNode>,\n    ) -> DomSlot {\n        macro_rules! key {\n            ($v:expr) => {\n                $v.key().expect(\"unkeyed child in fully keyed list\")\n            };\n        }\n        /// Find the first differing key in 2 iterators\n        fn matching_len<'a, 'b>(\n            a: impl Iterator<Item = &'a Key>,\n            b: impl Iterator<Item = &'b Key>,\n        ) -> usize {\n            a.zip(b).take_while(|(a, b)| a == b).count()\n        }\n\n        // Find first key mismatch from the back\n        let matching_len_end = matching_len(\n            left_vdoms.iter().map(|v| key!(v)).rev(),\n            rev_bundles.iter().map(|v| key!(v)),\n        );\n\n        if cfg!(debug_assertions) {\n            let mut keys = HashSet::with_capacity(left_vdoms.len());\n            for (idx, n) in left_vdoms.iter().enumerate() {\n                let key = key!(n);\n                debug_assert!(\n                    keys.insert(key!(n)),\n                    \"duplicate key detected: {key} at index {idx}. Keys in keyed lists must be \\\n                     unique!\",\n                );\n            }\n        }\n\n        // If there is no key mismatch, apply the unkeyed approach\n        // Corresponds to adding or removing items from the back of the list\n        if matching_len_end == std::cmp::min(left_vdoms.len(), rev_bundles.len()) {\n            // No key changes\n            return Self::apply_unkeyed(root, parent_scope, parent, slot, left_vdoms, rev_bundles);\n        }\n\n        // We partially drain the new vnodes in several steps.\n        let mut lefts = left_vdoms;\n        let mut writer = NodeWriter {\n            root,\n            parent_scope,\n            parent,\n            slot,\n        };\n        // Step 1. Diff matching children at the end\n        let lefts_to = lefts.len() - matching_len_end;\n        for (l, r) in lefts\n            .drain(lefts_to..)\n            .rev()\n            .zip(rev_bundles[..matching_len_end].iter_mut())\n        {\n            writer = writer.patch(l, r);\n        }\n\n        // Step 2. Diff matching children in the middle, that is between the first and last key\n        // mismatch Find first key mismatch from the front\n        let mut matching_len_start = matching_len(\n            lefts.iter().map(|v| key!(v)),\n            rev_bundles.iter().map(|v| key!(v)).rev(),\n        );\n\n        // Step 2.1. Splice out the existing middle part and build a lookup by key\n        let rights_to = rev_bundles.len() - matching_len_start;\n        let mut bundle_middle = matching_len_end..rights_to;\n        if bundle_middle.start > bundle_middle.end {\n            // If this range is \"inverted\", this implies that the incoming nodes in lefts contain a\n            // duplicate key!\n            // Pictogram:\n            //                                         v lefts_to\n            // lefts:              | SSSSSSSS | ------ | EEEEEEEE |\n            //                                ↕ matching_len_start\n            // rev_bundles.rev():  | SSS | ?? | EEE |\n            //                           ^ rights_to\n            // Both a key from the (S)tarting portion and (E)nding portion of lefts has matched a\n            // key in the ? portion of bundles. Since the former can't overlap, a key\n            // must be duplicate. Duplicates might lead to us forgetting about some\n            // bundles entirely. It is NOT straight forward to adjust the below code to\n            // consistently check and handle this. The duplicate keys might\n            // be in the start or end portion.\n            // With debug_assertions we can never reach this. For production code, hope for the best\n            // by pretending. We still need to adjust some things so splicing doesn't\n            // panic:\n            matching_len_start = 0;\n            bundle_middle = matching_len_end..rev_bundles.len();\n        }\n        let (matching_len_start, bundle_middle) = (matching_len_start, bundle_middle);\n\n        // BNode contains js objects that look suspicious to clippy but are harmless\n        #[allow(clippy::mutable_key_type)]\n        let mut spare_bundles: HashSet<KeyedEntry> = HashSet::with_capacity(bundle_middle.len());\n        let mut spliced_middle = rev_bundles.splice(bundle_middle, std::iter::empty());\n        for (idx, r) in (&mut spliced_middle).enumerate() {\n            #[cold]\n            fn duplicate_in_bundle(root: &BSubtree, parent: &Element, r: BNode) {\n                test_log!(\"removing: {:?}\", r);\n                r.detach(root, parent, false);\n            }\n            if let Some(KeyedEntry(_, dup)) = spare_bundles.replace(KeyedEntry(idx, r)) {\n                duplicate_in_bundle(root, parent, dup);\n            }\n        }\n\n        // Step 2.2. Put the middle part back together in the new key order\n        let mut replacements: Vec<BNode> = Vec::with_capacity((matching_len_start..lefts_to).len());\n        // The goal is to shift as few nodes as possible.\n\n        // We handle runs of in-order nodes. When we encounter one out-of-order, we decide whether:\n        // - to shift all nodes in the current run to the position after the node before of the run,\n        //   or to\n        // - \"commit\" to the current run, shift all nodes before the end of the run that we might\n        //   encounter in the future, and then start a new run.\n        // Example of a run:\n        //               barrier_idx --v                   v-- end_idx\n        // spliced_middle  [ ... , M , N , C , D , E , F , G , ... ] (original element order)\n        //                                 ^---^-----------^ the nodes that are part of the current\n        // run                           v start_writer\n        // replacements    [ ... , M , C , D , G ]                   (new element order)\n        //                             ^-- start_idx\n        let mut barrier_idx = 0; // nodes from spliced_middle[..barrier_idx] are shifted unconditionally\n        struct RunInformation<'a> {\n            start_writer: NodeWriter<'a>,\n            start_idx: usize,\n            end_idx: usize,\n        }\n        let mut current_run: Option<RunInformation<'_>> = None;\n\n        for l in lefts\n            .drain(matching_len_start..) // lefts_to.. has been drained\n            .rev()\n        {\n            let ancestor = spare_bundles.take(key!(l));\n            // Check if we need to shift or commit a run\n            if let Some(run) = current_run.as_mut() {\n                if let Some(KeyedEntry(idx, _)) = ancestor {\n                    // If there are only few runs, this is a cold path\n                    if idx < run.end_idx {\n                        // Have to decide whether to shift or commit the current run. A few\n                        // calculations: A perfect estimate of the amount of\n                        // nodes we have to shift if we move this run:\n                        let run_length = replacements.len() - run.start_idx;\n                        // A very crude estimate of the amount of nodes we will have to shift if we\n                        // commit the run: Note nodes of the current run\n                        // should not be counted here!\n                        let estimated_skipped_nodes = run.end_idx - idx.max(barrier_idx);\n                        // double run_length to counteract that the run is part of the\n                        // estimated_skipped_nodes\n                        if 2 * run_length > estimated_skipped_nodes {\n                            // less work to commit to this run\n                            barrier_idx = 1 + run.end_idx;\n                        } else {\n                            // Less work to shift this run\n                            for r in replacements[run.start_idx..].iter_mut().rev() {\n                                run.start_writer.shift(r);\n                            }\n                        }\n                        current_run = None;\n                    }\n                }\n            }\n            let bundle = if let Some(KeyedEntry(idx, mut r_bundle)) = ancestor {\n                match current_run.as_mut() {\n                    // hot path\n                    // We know that idx >= run.end_idx, so this node doesn't need to shift\n                    Some(run) => run.end_idx = idx,\n                    None => match idx.cmp(&barrier_idx) {\n                        // peep hole optimization, don't start a run as the element is already where\n                        // it should be\n                        Ordering::Equal => barrier_idx += 1,\n                        // shift the node unconditionally, don't start a run\n                        Ordering::Less => writer.shift(&r_bundle),\n                        // start a run\n                        Ordering::Greater => {\n                            current_run = Some(RunInformation {\n                                start_writer: writer.clone(),\n                                start_idx: replacements.len(),\n                                end_idx: idx,\n                            })\n                        }\n                    },\n                }\n                writer = writer.patch(l, &mut r_bundle);\n                r_bundle\n            } else {\n                // Even if there is an active run, we don't have to modify it\n                let (next_writer, bundle) = writer.add(l);\n                writer = next_writer;\n                bundle\n            };\n            replacements.push(bundle);\n        }\n        // drop the splice iterator and immediately replace the range with the reordered elements\n        drop(spliced_middle);\n        rev_bundles.splice(matching_len_end..matching_len_end, replacements);\n\n        // Step 2.3. Remove any extra rights\n        for KeyedEntry(_, r) in spare_bundles.drain() {\n            test_log!(\"removing: {:?}\", r);\n            r.detach(root, parent, false);\n        }\n\n        // Step 3. Diff matching children at the start\n        let rights_to = rev_bundles.len() - matching_len_start;\n        for (l, r) in lefts\n            .drain(..) // matching_len_start.. has been drained already\n            .rev()\n            .zip(rev_bundles[rights_to..].iter_mut())\n        {\n            writer = writer.patch(l, r);\n        }\n\n        writer.slot\n    }\n}\n\nimpl ReconcileTarget for BList {\n    fn detach(self, root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        for child in self.rev_children.into_iter() {\n            child.detach(root, parent, parent_to_detach);\n        }\n    }\n\n    fn shift(&self, next_parent: &Element, mut slot: DomSlot) -> DomSlot {\n        for node in self.rev_children.iter() {\n            slot = node.shift(next_parent, slot);\n        }\n\n        slot\n    }\n}\n\nimpl Reconcilable for VList {\n    type Bundle = BList;\n\n    fn attach(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let mut self_ = BList::new();\n        let node_ref = self.reconcile(root, parent_scope, parent, slot, &mut self_);\n        (node_ref, self_)\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        // 'Forcefully' pretend the existing node is a list. Creates a\n        // singleton list if it isn't already.\n        let blist = bundle.make_list();\n        self.reconcile(root, parent_scope, parent, slot, blist)\n    }\n\n    fn reconcile(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        blist: &mut BList,\n    ) -> DomSlot {\n        // Here, we will try to diff the previous list elements with the new\n        // ones we want to insert. For that, we will use two lists:\n        //  - lefts: new elements to render in the DOM\n        //  - rights: previously rendered elements.\n        //\n        // The left items are known since we want to insert them\n        // (self.children). For the right ones, we will look at the bundle,\n        // i.e. the current DOM list element that we want to replace with self.\n        let (key, fully_keyed, lefts) = self.split_for_blist();\n\n        let rights = &mut blist.rev_children;\n        test_log!(\"lefts: {:?}\", lefts);\n        test_log!(\"rights: {:?}\", rights);\n\n        if let Some(additional) = lefts.len().checked_sub(rights.len()) {\n            rights.reserve_exact(additional);\n        }\n        let first = if fully_keyed && blist.fully_keyed {\n            BList::apply_keyed(root, parent_scope, parent, slot, lefts, rights)\n        } else {\n            BList::apply_unkeyed(root, parent_scope, parent, slot, lefts, rights)\n        };\n        blist.fully_keyed = fully_keyed;\n        blist.key = key;\n        test_log!(\"result: {:?}\", rights);\n        first\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::{DynamicDomSlot, Fragment, Hydratable};\n\n    impl Hydratable for VList {\n        fn hydrate(\n            self,\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            let (key, fully_keyed, vchildren) = self.split_for_blist();\n\n            let mut children = Vec::with_capacity(vchildren.len());\n\n            for child in vchildren.into_iter() {\n                let child = child.hydrate(root, parent_scope, parent, fragment, prev_next_sibling);\n\n                children.push(child);\n            }\n\n            children.reverse();\n\n            BList {\n                rev_children: children,\n                fully_keyed,\n                key,\n            }\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    extern crate self as yew;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use crate::html;\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn diff() {\n        let layout1 = TestLayout {\n            name: \"1\",\n            node: html! {\n                <>\n                    {\"a\"}\n                    {\"b\"}\n                    <>\n                        {\"c\"}\n                        {\"d\"}\n                    </>\n                    {\"e\"}\n                </>\n            },\n            expected: \"abcde\",\n        };\n\n        let layout2 = TestLayout {\n            name: \"2\",\n            node: html! {\n                <>\n                    {\"a\"}\n                    {\"b\"}\n                    <></>\n                    {\"e\"}\n                    {\"f\"}\n                </>\n            },\n            expected: \"abef\",\n        };\n\n        let layout3 = TestLayout {\n            name: \"3\",\n            node: html! {\n                <>\n                    {\"a\"}\n                    <></>\n                    {\"b\"}\n                    {\"e\"}\n                </>\n            },\n            expected: \"abe\",\n        };\n\n        let layout4 = TestLayout {\n            name: \"4\",\n            node: html! {\n                <>\n                    {\"a\"}\n                    <>\n                        {\"c\"}\n                        {\"d\"}\n                    </>\n                    {\"b\"}\n                    {\"e\"}\n                </>\n            },\n            expected: \"acdbe\",\n        };\n\n        diff_layouts(vec![layout1, layout2, layout3, layout4]);\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests_keys {\n    extern crate self as yew;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n    use web_sys::Node;\n\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n    use crate::virtual_dom::VNode;\n    use crate::{html, Children, Component, Context, Html, Properties};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    struct Comp {}\n\n    #[derive(Properties, Clone, PartialEq)]\n    struct CountingCompProps {\n        id: usize,\n        #[prop_or(false)]\n        can_change: bool,\n    }\n\n    impl Component for Comp {\n        type Message = ();\n        type Properties = CountingCompProps;\n\n        fn create(_: &Context<Self>) -> Self {\n            Comp {}\n        }\n\n        fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n            unimplemented!();\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> Html {\n            html! { <p>{ ctx.props().id }</p> }\n        }\n    }\n\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct ListProps {\n        pub children: Children,\n    }\n\n    pub struct List();\n\n    impl Component for List {\n        type Message = ();\n        type Properties = ListProps;\n\n        fn create(_: &Context<Self>) -> Self {\n            Self()\n        }\n\n        fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n            unimplemented!();\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> Html {\n            html! { <>{ for ctx.props().children.iter() }</> }\n        }\n    }\n\n    #[test]\n    fn diff() {\n        let mut layouts = vec![];\n\n        let vref_node: Node = gloo::utils::document().create_element(\"i\").unwrap().into();\n        layouts.push(TestLayout {\n            name: \"All VNode types as children\",\n            node: html! {\n                <>\n                    {\"a\"}\n                    <span key=\"vtag\"></span>\n                    {\"c\"}\n                    {\"d\"}\n                    <Comp id=0 key=\"vchild\" />\n                    <key=\"vlist\">\n                        {\"foo\"}\n                        {\"bar\"}\n                    </>\n                    {VNode::VRef(vref_node)}\n                </>\n            },\n            expected: \"a<span></span>cd<p>0</p>foobar<i></i>\",\n        });\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Inserting into VList first child - before\",\n                node: html! {\n                    <>\n                        <key=\"VList\">\n                            <i key=\"i\"></i>\n                        </>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<i></i><p></p>\",\n            },\n            TestLayout {\n                name: \"Inserting into VList first child - after\",\n                node: html! {\n                    <>\n                        <key=\"VList\">\n                            <i key=\"i\"></i>\n                            <e key=\"e\"></e>\n                        </>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"No matches - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                    </>\n                },\n                expected: \"<i></i><e></e>\",\n            },\n            TestLayout {\n                name: \"No matches - after\",\n                node: html! {\n                    <>\n                        <a key=\"a\"></a>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<a></a><p></p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Append - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                    </>\n                },\n                expected: \"<i></i><e></e>\",\n            },\n            TestLayout {\n                name: \"Append - after\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Prepend - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                    </>\n                },\n                expected: \"<i></i><e></e>\",\n            },\n            TestLayout {\n                name: \"Prepend - after\",\n                node: html! {\n                    <>\n                        <p key=\"p\"></p>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                    </>\n                },\n                expected: \"<p></p><i></i><e></e>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Delete first - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p>\",\n            },\n            TestLayout {\n                name: \"Delete first - after\",\n                node: html! {\n                    <>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<e></e><p></p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Delete last - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p>\",\n            },\n            TestLayout {\n                name: \"Delete last - after\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                    </>\n                },\n                expected: \"<i></i><e></e>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Delete last and change node type - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p>\",\n            },\n            TestLayout {\n                name: \"Delete last - after\",\n                node: html! {\n                    <>\n                        <List key=\"i\"><i/></List>\n                        <List key=\"e\"><e/></List>\n                        <List key=\"a\"><a/></List>\n                    </>\n                },\n                expected: \"<i></i><e></e><a></a>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Delete middle - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                        <a key=\"a\"></a>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a>\",\n            },\n            TestLayout {\n                name: \"Delete middle - after\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e2\"></e>\n                        <p key=\"p2\"></p>\n                        <a key=\"a\"></a>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Delete middle and change node type - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                        <a key=\"a\"></a>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a>\",\n            },\n            TestLayout {\n                name: \"Delete middle and change node type- after\",\n                node: html! {\n                    <>\n                        <List key=\"i2\"><i/></List>\n                        <e key=\"e\"></e>\n                        <List key=\"p\"><p/></List>\n                        <List key=\"a2\"><a/></List>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Reverse - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <e key=\"e\"></e>\n                        <p key=\"p\"></p>\n                        <u key=\"u\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><u></u>\",\n            },\n            TestLayout {\n                name: \"Reverse - after\",\n                node: html! {\n                    <>\n                        <u key=\"u\"></u>\n                        <p key=\"p\"></p>\n                        <e key=\"e\"></e>\n                        <i key=\"i\"></i>\n                    </>\n                },\n                expected: \"<u></u><p></p><e></e><i></i>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Reverse and change node type - before\",\n                node: html! {\n                    <>\n                        <i key=\"i\"></i>\n                        <key=\"i1\"></>\n                        <key=\"i2\"></>\n                        <key=\"i3\"></>\n                        <e key=\"e\"></e>\n                        <key=\"yo\">\n                            <p key=\"p\"></p>\n                        </>\n                        <u key=\"u\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><u></u>\",\n            },\n            TestLayout {\n                name: \"Reverse and change node type - after\",\n                node: html! {\n                    <>\n                        <List key=\"u\"><u/></List>\n                        <List key=\"p\"><p/></List>\n                        <List key=\"e\"><e/></List>\n                        <List key=\"i\"><i/></List>\n                    </>\n                },\n                expected: \"<u></u><p></p><e></e><i></i>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap 1&2 - before\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap 1&2 - after\",\n                node: html! {\n                    <>\n                        <e key=\"2\"></e>\n                        <i key=\"1\"></i>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<e></e><i></i><p></p><a></a><u></u>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap 1&2 and change node type - before\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap 1&2 and change node type - after\",\n                node: html! {\n                    <>\n                        <List key=\"2\"><e/></List>\n                        <List key=\"1\"><i/></List>\n                        <List key=\"3\"><p/></List>\n                        <List key=\"4\"><a/></List>\n                        <List key=\"5\"><u/></List>\n                    </>\n                },\n                expected: \"<e></e><i></i><p></p><a></a><u></u>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"test - before\",\n                node: html! {\n                    <>\n                        <key=\"1\">\n                            <e key=\"e\"></e>\n                            <p key=\"p\"></p>\n                            <a key=\"a\"></a>\n                            <u key=\"u\"></u>\n                        </>\n                        <key=\"2\">\n                            <e key=\"e\"></e>\n                            <p key=\"p\"></p>\n                            <a key=\"a\"></a>\n                            <u key=\"u\"></u>\n                        </>\n                    </>\n                },\n                expected: \"<e></e><p></p><a></a><u></u><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap 4&5 - after\",\n                node: html! {\n                    <>\n                        <e key=\"1\"></e>\n                        <key=\"2\">\n                            <p key=\"p\"></p>\n                            <i key=\"i\"></i>\n                        </>\n                    </>\n                },\n                expected: \"<e></e><p></p><i></i>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap 4&5 - before\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap 4&5 - after\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <u key=\"5\"></u>\n                        <a key=\"4\"></a>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><u></u><a></a>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap 1&5 - before\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap 1&5 - after\",\n                node: html! {\n                    <>\n                        <u key=\"5\"></u>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <i key=\"1\"></i>\n                    </>\n                },\n                expected: \"<u></u><e></e><p></p><a></a><i></i>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Move 2 after 4 - before\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Move 2 after 4 - after\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <e key=\"2\"></e>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><p></p><a></a><e></e><u></u>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap 1,2 <-> 3,4 - before\",\n                node: html! {\n                    <>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap 1,2 <-> 3,4 - after\",\n                node: html! {\n                    <>\n                        <p key=\"3\"></p>\n                        <a key=\"4\"></a>\n                        <i key=\"1\"></i>\n                        <e key=\"2\"></e>\n                        <u key=\"5\"></u>\n                    </>\n                },\n                expected: \"<p></p><a></a><i></i><e></e><u></u>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap lists - before\",\n                node: html! {\n                    <>\n                        <key=\"1\">\n                            <i></i>\n                            <e></e>\n                        </>\n                        <key=\"2\">\n                            <a></a>\n                            <u></u>\n                        </>\n                    </>\n                },\n                expected: \"<i></i><e></e><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap lists - after\",\n                node: html! {\n                    <>\n                        <key=\"2\">\n                            <a></a>\n                            <u></u>\n                        </>\n                        <key=\"1\">\n                            <i></i>\n                            <e></e>\n                        </>\n                    </>\n                },\n                expected: \"<a></a><u></u><i></i><e></e>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Swap lists with in-between - before\",\n                node: html! {\n                    <>\n                        <key=\"1\">\n                            <i></i>\n                            <e></e>\n                        </>\n                        <p key=\"between\"></p>\n                        <key=\"2\">\n                            <a></a>\n                            <u></u>\n                        </>\n                    </>\n                },\n                expected: \"<i></i><e></e><p></p><a></a><u></u>\",\n            },\n            TestLayout {\n                name: \"Swap lists with in-between - after\",\n                node: html! {\n                    <>\n                        <key=\"2\">\n                            <a></a>\n                            <u></u>\n                        </>\n                        <p key=\"between\"></p>\n                        <key=\"1\">\n                            <i></i>\n                            <e></e>\n                        </>\n                    </>\n                },\n                expected: \"<a></a><u></u><p></p><i></i><e></e>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Insert VComp front - before\",\n                node: html! {\n                    <>\n                        <u key=1></u>\n                        <a key=2></a>\n                    </>\n                },\n                expected: \"<u></u><a></a>\",\n            },\n            TestLayout {\n                name: \"Insert VComp front - after\",\n                node: html! {\n                    <>\n                        <Comp id=0 key=\"comp\"/>\n                        <u key=1></u>\n                        <a key=2></a>\n                    </>\n                },\n                expected: \"<p>0</p><u></u><a></a>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Insert VComp middle - before\",\n                node: html! {\n                    <>\n                        <u key=1></u>\n                        <a key=2></a>\n                    </>\n                },\n                expected: \"<u></u><a></a>\",\n            },\n            TestLayout {\n                name: \"Insert VComp middle - after\",\n                node: html! {\n                    <>\n                        <u key=1></u>\n                        <Comp id=0 key=\"comp\"/>\n                        <a key=2></a>\n                    </>\n                },\n                expected: \"<u></u><p>0</p><a></a>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Insert VComp back - before\",\n                node: html! {\n                    <>\n                        <u key=1></u>\n                        <a key=2></a>\n                    </>\n                },\n                expected: \"<u></u><a></a>\",\n            },\n            TestLayout {\n                name: \"Insert VComp back - after\",\n                node: html! {\n                    <>\n                        <u key=1></u>\n                        <a key=2></a>\n                        <Comp id=0 key=\"comp\"/>\n                    </>\n                },\n                expected: \"<u></u><a></a><p>0</p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Reverse VComp children - before\",\n                node: html! {\n                    <>\n                        <Comp id=1 key=\"comp-1\"/>\n                        <Comp id=2 key=\"comp-2\"/>\n                        <Comp id=3 key=\"comp-3\"/>\n                    </>\n                },\n                expected: \"<p>1</p><p>2</p><p>3</p>\",\n            },\n            TestLayout {\n                name: \"Reverse VComp children - after\",\n                node: html! {\n                    <>\n                        <Comp id=3 key=\"comp-3\"/>\n                        <Comp id=2 key=\"comp-2\"/>\n                        <Comp id=1 key=\"comp-1\"/>\n                    </>\n                },\n                expected: \"<p>3</p><p>2</p><p>1</p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Reverse VComp children with children - before\",\n                node: html! {\n                    <>\n                        <List key=\"comp-1\"><p>{\"11\"}</p><p>{\"12\"}</p></List>\n                        <List key=\"comp-2\"><p>{\"21\"}</p><p>{\"22\"}</p></List>\n                        <List key=\"comp-3\"><p>{\"31\"}</p><p>{\"32\"}</p></List>\n                    </>\n                },\n                expected: \"<p>11</p><p>12</p><p>21</p><p>22</p><p>31</p><p>32</p>\",\n            },\n            TestLayout {\n                name: \"Reverse VComp children with children - after\",\n                node: html! {\n                    <>\n                        <List key=\"comp-3\"><p>{\"31\"}</p><p>{\"32\"}</p></List>\n                        <List key=\"comp-2\"><p>{\"21\"}</p><p>{\"22\"}</p></List>\n                        <List key=\"comp-1\"><p>{\"11\"}</p><p>{\"12\"}</p></List>\n                    </>\n                },\n                expected: \"<p>31</p><p>32</p><p>21</p><p>22</p><p>11</p><p>12</p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Complex component update - before\",\n                node: html! {\n                    <List>\n                        <Comp id=1 key=\"comp-1\"/>\n                        <Comp id=2 key=\"comp-2\"/>\n                    </List>\n                },\n                expected: \"<p>1</p><p>2</p>\",\n            },\n            TestLayout {\n                name: \"Complex component update - after\",\n                node: html! {\n                    <List>\n                        <List key=\"comp-1\">\n                            <Comp id=1 />\n                        </List>\n                        <List key=\"comp-2\">\n                            <p>{\"2\"}</p>\n                        </List>\n                    </List>\n                },\n                expected: \"<p>1</p><p>2</p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Reorder VComp children with children - before\",\n                node: html! {\n                    <>\n                        <List key=\"comp-1\"><p>{\"1\"}</p></List>\n                        <List key=\"comp-3\"><p>{\"3\"}</p></List>\n                        <List key=\"comp-5\"><p>{\"5\"}</p></List>\n                        <List key=\"comp-2\"><p>{\"2\"}</p></List>\n                        <List key=\"comp-4\"><p>{\"4\"}</p></List>\n                        <List key=\"comp-6\"><p>{\"6\"}</p></List>\n                    </>\n                },\n                expected: \"<p>1</p><p>3</p><p>5</p><p>2</p><p>4</p><p>6</p>\",\n            },\n            TestLayout {\n                name: \"Reorder VComp children with children - after\",\n                node: html! {\n                    <>\n                        <Comp id=6 key=\"comp-6\"/>\n                        <Comp id=5 key=\"comp-5\"/>\n                        <Comp id=4 key=\"comp-4\"/>\n                        <Comp id=3 key=\"comp-3\"/>\n                        <Comp id=2 key=\"comp-2\"/>\n                        <Comp id=1 key=\"comp-1\"/>\n                    </>\n                },\n                expected: \"<p>6</p><p>5</p><p>4</p><p>3</p><p>2</p><p>1</p>\",\n            },\n        ]);\n\n        layouts.extend(vec![\n            TestLayout {\n                name: \"Replace and reorder components - before\",\n                node: html! {\n                    <List>\n                        <List key=\"comp-1\"><p>{\"1\"}</p></List>\n                        <List key=\"comp-2\"><p>{\"2\"}</p></List>\n                        <List key=\"comp-3\"><p>{\"3\"}</p></List>\n                    </List>\n                },\n                expected: \"<p>1</p><p>2</p><p>3</p>\",\n            },\n            TestLayout {\n                name: \"Replace and reorder components - after\",\n                node: html! {\n                    <List>\n                        <Comp id=3 key=\"comp-3\" />\n                        <Comp id=2 key=\"comp-2\" />\n                        <Comp id=1 key=\"comp-1\" />\n                    </List>\n                },\n                expected: \"<p>3</p><p>2</p><p>1</p>\",\n            },\n        ]);\n\n        diff_layouts(layouts);\n    }\n\n    #[test]\n    //#[should_panic(expected = \"duplicate key detected: vtag at index 1\")]\n    // can't inspect panic message in wasm :/\n    #[should_panic]\n    fn duplicate_keys() {\n        let mut layouts = vec![];\n\n        layouts.push(TestLayout {\n            name: \"A list with duplicate keys\",\n            node: html! {\n                <>\n                    <i key=\"vtag\" />\n                    <i key=\"vtag\" />\n                </>\n            },\n            expected: \"<i></i><i></i>\",\n        });\n\n        diff_layouts(layouts);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/bnode.rs",
    "content": "//! This module contains the bundle version of an abstract node [BNode]\n\nuse std::fmt;\n\nuse web_sys::{Element, Node};\n\nuse super::{BComp, BList, BPortal, BRaw, BSubtree, BSuspense, BTag, BText, DomSlot};\nuse crate::dom_bundle::{Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\nuse crate::utils::RcExt;\nuse crate::virtual_dom::{Key, VNode};\n\n/// The bundle implementation to [VNode].\npub(super) enum BNode {\n    /// A bind between `VTag` and `Element`.\n    Tag(Box<BTag>),\n    /// A bind between `VText` and `TextNode`.\n    Text(BText),\n    /// A bind between `VComp` and `Element`.\n    Comp(BComp),\n    /// A holder for a list of other nodes.\n    List(BList),\n    /// A portal to another part of the document\n    Portal(BPortal),\n    /// A holder for any `Node` (necessary for replacing node).\n    Ref(Node),\n    /// A suspendible document fragment.\n    Suspense(Box<BSuspense>),\n    /// A raw HTML string, represented by [`AttrValue`](crate::AttrValue).\n    Raw(BRaw),\n}\n\nimpl BNode {\n    /// Get the key of the underlying node\n    pub fn key(&self) -> Option<&Key> {\n        match self {\n            Self::Comp(bsusp) => bsusp.key(),\n            Self::List(blist) => blist.key(),\n            Self::Ref(_) => None,\n            Self::Tag(btag) => btag.key(),\n            Self::Text(_) => None,\n            Self::Portal(bportal) => bportal.key(),\n            Self::Suspense(bsusp) => bsusp.key(),\n            Self::Raw(_) => None,\n        }\n    }\n}\n\nimpl ReconcileTarget for BNode {\n    /// Remove VNode from parent.\n    fn detach(self, root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        match self {\n            Self::Tag(vtag) => vtag.detach(root, parent, parent_to_detach),\n            Self::Text(btext) => btext.detach(root, parent, parent_to_detach),\n            Self::Comp(bsusp) => bsusp.detach(root, parent, parent_to_detach),\n            Self::List(blist) => blist.detach(root, parent, parent_to_detach),\n            Self::Ref(ref node) => {\n                // Always remove user-defined nodes to clear possible parent references of them\n                if parent.remove_child(node).is_err() {\n                    tracing::warn!(\"Node not found to remove VRef\");\n                }\n            }\n            Self::Portal(bportal) => bportal.detach(root, parent, parent_to_detach),\n            Self::Suspense(bsusp) => bsusp.detach(root, parent, parent_to_detach),\n            Self::Raw(raw) => raw.detach(root, parent, parent_to_detach),\n        }\n    }\n\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        match self {\n            Self::Tag(ref vtag) => vtag.shift(next_parent, slot),\n            Self::Text(ref btext) => btext.shift(next_parent, slot),\n            Self::Comp(ref bsusp) => bsusp.shift(next_parent, slot),\n            Self::List(ref vlist) => vlist.shift(next_parent, slot),\n            Self::Ref(ref node) => {\n                slot.insert(next_parent, node);\n\n                DomSlot::at(node.clone())\n            }\n            Self::Portal(ref vportal) => vportal.shift(next_parent, slot),\n            Self::Suspense(ref vsuspense) => vsuspense.shift(next_parent, slot),\n            Self::Raw(ref braw) => braw.shift(next_parent, slot),\n        }\n    }\n}\n\nimpl Reconcilable for VNode {\n    type Bundle = BNode;\n\n    fn attach(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        match self {\n            VNode::VTag(vtag) => {\n                let (node_ref, tag) =\n                    RcExt::unwrap_or_clone(vtag).attach(root, parent_scope, parent, slot);\n                (node_ref, tag.into())\n            }\n            VNode::VText(vtext) => {\n                let (node_ref, text) = vtext.attach(root, parent_scope, parent, slot);\n                (node_ref, text.into())\n            }\n            VNode::VComp(vcomp) => {\n                let (node_ref, comp) =\n                    RcExt::unwrap_or_clone(vcomp).attach(root, parent_scope, parent, slot);\n                (node_ref, comp.into())\n            }\n            VNode::VList(vlist) => {\n                let (node_ref, list) =\n                    RcExt::unwrap_or_clone(vlist).attach(root, parent_scope, parent, slot);\n                (node_ref, list.into())\n            }\n            VNode::VRef(node) => {\n                slot.insert(parent, &node);\n                (DomSlot::at(node.clone()), BNode::Ref(node))\n            }\n            VNode::VPortal(vportal) => {\n                let (node_ref, portal) =\n                    RcExt::unwrap_or_clone(vportal).attach(root, parent_scope, parent, slot);\n                (node_ref, portal.into())\n            }\n            VNode::VSuspense(vsuspsense) => {\n                let (node_ref, suspsense) =\n                    RcExt::unwrap_or_clone(vsuspsense).attach(root, parent_scope, parent, slot);\n                (node_ref, suspsense.into())\n            }\n            VNode::VRaw(vraw) => {\n                let (node_ref, raw) = vraw.attach(root, parent_scope, parent, slot);\n                (node_ref, raw.into())\n            }\n        }\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        self.reconcile(root, parent_scope, parent, slot, bundle)\n    }\n\n    fn reconcile(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        match self {\n            VNode::VTag(vtag) => RcExt::unwrap_or_clone(vtag).reconcile_node(\n                root,\n                parent_scope,\n                parent,\n                slot,\n                bundle,\n            ),\n            VNode::VText(vtext) => vtext.reconcile_node(root, parent_scope, parent, slot, bundle),\n            VNode::VComp(vcomp) => RcExt::unwrap_or_clone(vcomp).reconcile_node(\n                root,\n                parent_scope,\n                parent,\n                slot,\n                bundle,\n            ),\n            VNode::VList(vlist) => RcExt::unwrap_or_clone(vlist).reconcile_node(\n                root,\n                parent_scope,\n                parent,\n                slot,\n                bundle,\n            ),\n            VNode::VRef(node) => match bundle {\n                BNode::Ref(ref n) if &node == n => DomSlot::at(node),\n                _ => VNode::VRef(node).replace(root, parent_scope, parent, slot, bundle),\n            },\n            VNode::VPortal(vportal) => RcExt::unwrap_or_clone(vportal).reconcile_node(\n                root,\n                parent_scope,\n                parent,\n                slot,\n                bundle,\n            ),\n            VNode::VSuspense(vsuspsense) => RcExt::unwrap_or_clone(vsuspsense).reconcile_node(\n                root,\n                parent_scope,\n                parent,\n                slot,\n                bundle,\n            ),\n            VNode::VRaw(vraw) => vraw.reconcile_node(root, parent_scope, parent, slot, bundle),\n        }\n    }\n}\n\nimpl From<BText> for BNode {\n    #[inline]\n    fn from(btext: BText) -> Self {\n        Self::Text(btext)\n    }\n}\n\nimpl From<BList> for BNode {\n    #[inline]\n    fn from(blist: BList) -> Self {\n        Self::List(blist)\n    }\n}\n\nimpl From<BTag> for BNode {\n    #[inline]\n    fn from(btag: BTag) -> Self {\n        Self::Tag(Box::new(btag))\n    }\n}\n\nimpl From<BComp> for BNode {\n    #[inline]\n    fn from(bcomp: BComp) -> Self {\n        Self::Comp(bcomp)\n    }\n}\n\nimpl From<BPortal> for BNode {\n    #[inline]\n    fn from(bportal: BPortal) -> Self {\n        Self::Portal(bportal)\n    }\n}\n\nimpl From<BSuspense> for BNode {\n    #[inline]\n    fn from(bsusp: BSuspense) -> Self {\n        Self::Suspense(Box::new(bsusp))\n    }\n}\n\nimpl From<BRaw> for BNode {\n    #[inline]\n    fn from(braw: BRaw) -> Self {\n        Self::Raw(braw)\n    }\n}\n\nimpl fmt::Debug for BNode {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            Self::Tag(ref vtag) => vtag.fmt(f),\n            Self::Text(ref btext) => btext.fmt(f),\n            Self::Comp(ref bsusp) => bsusp.fmt(f),\n            Self::List(ref vlist) => vlist.fmt(f),\n            Self::Ref(ref vref) => write!(f, \"VRef ( \\\"{}\\\" )\", crate::utils::print_node(vref)),\n            Self::Portal(ref vportal) => vportal.fmt(f),\n            Self::Suspense(ref bsusp) => bsusp.fmt(f),\n            Self::Raw(ref braw) => braw.fmt(f),\n        }\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::{DynamicDomSlot, Fragment, Hydratable};\n\n    impl Hydratable for VNode {\n        fn hydrate(\n            self,\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            match self {\n                VNode::VTag(vtag) => RcExt::unwrap_or_clone(vtag)\n                    .hydrate(root, parent_scope, parent, fragment, prev_next_sibling)\n                    .into(),\n                VNode::VText(vtext) => vtext\n                    .hydrate(root, parent_scope, parent, fragment, prev_next_sibling)\n                    .into(),\n                VNode::VComp(vcomp) => RcExt::unwrap_or_clone(vcomp)\n                    .hydrate(root, parent_scope, parent, fragment, prev_next_sibling)\n                    .into(),\n                VNode::VList(vlist) => RcExt::unwrap_or_clone(vlist)\n                    .hydrate(root, parent_scope, parent, fragment, prev_next_sibling)\n                    .into(),\n                // You cannot hydrate a VRef.\n                VNode::VRef(_) => {\n                    panic!(\n                        \"VRef is not hydratable. Try moving it to a component mounted after an \\\n                         effect.\"\n                    )\n                }\n                // You cannot hydrate a VPortal.\n                VNode::VPortal(_) => {\n                    panic!(\n                        \"VPortal is not hydratable. Try creating your portal by delaying it with \\\n                         use_effect.\"\n                    )\n                }\n                VNode::VSuspense(vsuspense) => RcExt::unwrap_or_clone(vsuspense)\n                    .hydrate(root, parent_scope, parent, fragment, prev_next_sibling)\n                    .into(),\n                VNode::VRaw(vraw) => vraw\n                    .hydrate(root, parent_scope, parent, fragment, prev_next_sibling)\n                    .into(),\n            }\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use super::*;\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn diff() {\n        let document = gloo::utils::document();\n        let vref_node_1 = VNode::VRef(document.create_element(\"i\").unwrap().into());\n        let vref_node_2 = VNode::VRef(document.create_element(\"b\").unwrap().into());\n\n        let layout1 = TestLayout {\n            name: \"1\",\n            node: vref_node_1,\n            expected: \"<i></i>\",\n        };\n\n        let layout2 = TestLayout {\n            name: \"2\",\n            node: vref_node_2,\n            expected: \"<b></b>\",\n        };\n\n        diff_layouts(vec![layout1, layout2]);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/bportal.rs",
    "content": "//! This module contains the bundle implementation of a portal [BPortal].\n\nuse web_sys::{Element, Node};\n\nuse super::{test_log, BNode, BSubtree, DomSlot};\nuse crate::dom_bundle::{Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\nuse crate::virtual_dom::{Key, VPortal};\n\n/// The bundle implementation to [VPortal].\n#[derive(Debug)]\npub struct BPortal {\n    // The inner root\n    inner_root: BSubtree,\n    /// The element under which the content is inserted.\n    host: Element,\n    /// The next sibling after the inserted content\n    inner_sibling: Option<Node>,\n    /// The inserted node\n    node: Box<BNode>,\n}\n\nimpl ReconcileTarget for BPortal {\n    fn detach(self, _root: &BSubtree, _parent: &Element, _parent_to_detach: bool) {\n        test_log!(\"Detaching portal from host\",);\n        self.node.detach(&self.inner_root, &self.host, false);\n    }\n\n    fn shift(&self, _next_parent: &Element, slot: DomSlot) -> DomSlot {\n        // portals have nothing in its original place of DOM, we also do nothing.\n        slot\n    }\n}\n\nimpl Reconcilable for VPortal {\n    type Bundle = BPortal;\n\n    fn attach(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        host_slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let Self {\n            host,\n            inner_sibling,\n            node,\n        } = self;\n        let inner_slot = DomSlot::create(inner_sibling.clone());\n        let inner_root = root.create_subroot(parent.clone(), &host);\n        let (_, inner) = node.attach(&inner_root, parent_scope, &host, inner_slot);\n        (\n            host_slot,\n            BPortal {\n                inner_root,\n                host,\n                node: Box::new(inner),\n                inner_sibling,\n            },\n        )\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        match bundle {\n            BNode::Portal(portal) => self.reconcile(root, parent_scope, parent, slot, portal),\n            _ => self.replace(root, parent_scope, parent, slot, bundle),\n        }\n    }\n\n    fn reconcile(\n        self,\n        _root: &BSubtree,\n        parent_scope: &AnyScope,\n        _parent: &Element,\n        host_slot: DomSlot,\n        portal: &mut Self::Bundle,\n    ) -> DomSlot {\n        let Self {\n            host,\n            inner_sibling,\n            node,\n        } = self;\n\n        let old_host = std::mem::replace(&mut portal.host, host);\n\n        let should_shift = old_host != portal.host || portal.inner_sibling != inner_sibling;\n        portal.inner_sibling = inner_sibling;\n        let inner_slot = DomSlot::create(portal.inner_sibling.clone());\n\n        if should_shift {\n            // Remount the inner node somewhere else instead of diffing\n            // Move the node, but keep the state\n            portal.node.shift(&portal.host, inner_slot.clone());\n        }\n        node.reconcile_node(\n            &portal.inner_root,\n            parent_scope,\n            &portal.host,\n            inner_slot,\n            &mut portal.node,\n        );\n        host_slot\n    }\n}\n\nimpl BPortal {\n    /// Get the key of the underlying portal\n    pub fn key(&self) -> Option<&Key> {\n        self.node.key()\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    extern crate self as yew;\n\n    use std::rc::Rc;\n\n    use gloo::utils::document;\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n    use web_sys::HtmlInputElement;\n    use yew::virtual_dom::VPortal;\n\n    use super::*;\n    use crate::html::NodeRef;\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n    use crate::virtual_dom::VNode;\n    use crate::{create_portal, html};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn diff() {\n        let mut layouts = vec![];\n        let first_target = gloo::utils::document().create_element(\"i\").unwrap();\n        let second_target = gloo::utils::document().create_element(\"o\").unwrap();\n        let target_with_child = gloo::utils::document().create_element(\"i\").unwrap();\n        let target_child = gloo::utils::document().create_element(\"s\").unwrap();\n        target_with_child.append_child(&target_child).unwrap();\n\n        layouts.push(TestLayout {\n            name: \"Portal - first target\",\n            node: html! {\n                <div>\n                    {VNode::VRef(first_target.clone().into())}\n                    {VNode::VRef(second_target.clone().into())}\n                    {VNode::VPortal(Rc::new(VPortal::new(\n                        html! { {\"PORTAL\"} },\n                        first_target.clone(),\n                    )))}\n                    {\"AFTER\"}\n                </div>\n            },\n            expected: \"<div><i>PORTAL</i><o></o>AFTER</div>\",\n        });\n        layouts.push(TestLayout {\n            name: \"Portal - second target\",\n            node: html! {\n                <div>\n                    {VNode::VRef(first_target.clone().into())}\n                    {VNode::VRef(second_target.clone().into())}\n                    {VNode::VPortal(Rc::new(VPortal::new(\n                        html! { {\"PORTAL\"} },\n                        second_target.clone(),\n                    )))}\n                    {\"AFTER\"}\n                </div>\n            },\n            expected: \"<div><i></i><o>PORTAL</o>AFTER</div>\",\n        });\n        layouts.push(TestLayout {\n            name: \"Portal - update inner content\",\n            node: html! {\n                <div>\n                    {VNode::VRef(first_target.clone().into())}\n                    {VNode::VRef(second_target.clone().into())}\n                    {VNode::VPortal(Rc::new(VPortal::new(\n                        html! { <> {\"PORTAL\"} <b /> </> },\n                        second_target.clone(),\n                    )))}\n                    {\"AFTER\"}\n                </div>\n            },\n            expected: \"<div><i></i><o>PORTAL<b></b></o>AFTER</div>\",\n        });\n        layouts.push(TestLayout {\n            name: \"Portal - replaced by text\",\n            node: html! {\n                <div>\n                    {VNode::VRef(first_target.clone().into())}\n                    {VNode::VRef(second_target.clone().into())}\n                    {\"FOO\"}\n                    {\"AFTER\"}\n                </div>\n            },\n            expected: \"<div><i></i><o></o>FOOAFTER</div>\",\n        });\n        layouts.push(TestLayout {\n            name: \"Portal - next sibling\",\n            node: html! {\n                <div>\n                    {VNode::VRef(target_with_child.clone().into())}\n                    {VNode::VPortal(Rc::new(VPortal::new_before(\n                        html! { {\"PORTAL\"} },\n                        target_with_child.clone(),\n                        Some(target_child.clone().into()),\n                    )))}\n                </div>\n            },\n            expected: \"<div><i>PORTAL<s></s></i></div>\",\n        });\n\n        diff_layouts(layouts)\n    }\n\n    fn setup_parent_with_portal() -> (BSubtree, AnyScope, Element, Element) {\n        let scope = AnyScope::test();\n        let parent = document().create_element(\"div\").unwrap();\n        let portal_host = document().create_element(\"div\").unwrap();\n        let root = BSubtree::create_root(&parent);\n\n        let body = document().body().unwrap();\n        body.append_child(&parent).unwrap();\n        body.append_child(&portal_host).unwrap();\n\n        (root, scope, parent, portal_host)\n    }\n\n    #[test]\n    fn test_no_shift() {\n        // Portals shouldn't shift (which e.g. causes internal inputs to unfocus) when sibling\n        // doesn't change.\n        let (root, scope, parent, portal_host) = setup_parent_with_portal();\n        let input_ref = NodeRef::default();\n\n        let portal = create_portal(\n            html! { <input type=\"text\" ref={&input_ref} /> },\n            portal_host,\n        );\n        let (_, mut bundle) = portal\n            .clone()\n            .attach(&root, &scope, &parent, DomSlot::at_end());\n\n        // Focus the input, then reconcile again\n        let input_el = input_ref.cast::<HtmlInputElement>().unwrap();\n        input_el.focus().unwrap();\n\n        let _ = portal.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut bundle);\n\n        let new_input_el = input_ref.cast::<HtmlInputElement>().unwrap();\n        assert_eq!(input_el, new_input_el);\n        assert_eq!(document().active_element(), Some(new_input_el.into()));\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/braw.rs",
    "content": "use wasm_bindgen::JsCast;\nuse web_sys::{Element, Node};\n\nuse super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\nuse crate::virtual_dom::vtag::{MATHML_NAMESPACE, SVG_NAMESPACE};\nuse crate::virtual_dom::VRaw;\nuse crate::AttrValue;\n\n#[derive(Debug)]\npub struct BRaw {\n    reference: Option<Node>,\n    children_count: usize,\n    html: AttrValue,\n}\n\nimpl BRaw {\n    fn create_elements(html: &str, parent_namespace: Option<&str>) -> Vec<Node> {\n        let div = if parent_namespace.is_some() {\n            gloo::utils::document()\n                .create_element_ns(parent_namespace, \"div\")\n                .unwrap()\n        } else {\n            gloo::utils::document().create_element(\"div\").unwrap()\n        };\n        div.set_inner_html(html);\n        let children = div.child_nodes();\n        let children = js_sys::Array::from(&children);\n        let children = children.to_vec();\n        children\n            .into_iter()\n            .map(|it| it.unchecked_into())\n            .collect::<Vec<_>>()\n    }\n\n    fn detach_bundle(&self, parent: &Element) {\n        let mut next_node = self.reference.clone();\n        for _ in 0..self.children_count {\n            if let Some(node) = next_node {\n                next_node = node.next_sibling();\n                parent.remove_child(&node).unwrap();\n            }\n        }\n    }\n\n    fn position(&self, next_slot: DomSlot) -> DomSlot {\n        self.reference\n            .as_ref()\n            .map(|n| DomSlot::at(n.clone()))\n            .unwrap_or(next_slot)\n    }\n}\n\nimpl ReconcileTarget for BRaw {\n    fn detach(self, _root: &BSubtree, parent: &Element, _parent_to_detach: bool) {\n        self.detach_bundle(parent);\n    }\n\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        let mut next_node = self.reference.clone();\n        for _ in 0..self.children_count {\n            if let Some(node) = next_node {\n                next_node = node.next_sibling();\n                slot.insert(next_parent, &node);\n            }\n        }\n        self.position(slot)\n    }\n}\n\nimpl Reconcilable for VRaw {\n    type Bundle = BRaw;\n\n    fn attach(\n        self,\n        _root: &BSubtree,\n        _parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let namespace = if parent.namespace_uri().is_some_and(|ns| ns == SVG_NAMESPACE) {\n            Some(SVG_NAMESPACE)\n        } else if parent\n            .namespace_uri()\n            .is_some_and(|ns| ns == MATHML_NAMESPACE)\n        {\n            Some(MATHML_NAMESPACE)\n        } else {\n            None\n        };\n\n        let elements = BRaw::create_elements(&self.html, namespace);\n        let count = elements.len();\n        let mut iter = elements.into_iter();\n        let reference = iter.next();\n        if let Some(ref first) = reference {\n            slot.insert(parent, first);\n            for ref child in iter {\n                slot.insert(parent, child);\n            }\n        }\n        let this = BRaw {\n            reference,\n            children_count: count,\n            html: self.html,\n        };\n        (this.position(slot), this)\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        match bundle {\n            BNode::Raw(raw) if raw.html == self.html => raw.position(slot),\n            BNode::Raw(raw) => self.reconcile(root, parent_scope, parent, slot, raw),\n            _ => self.replace(root, parent_scope, parent, slot, bundle),\n        }\n    }\n\n    fn reconcile(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut Self::Bundle,\n    ) -> DomSlot {\n        if self.html != bundle.html {\n            // we don't have a way to diff what's changed in the string so we remove the node and\n            // reattach it\n            bundle.detach_bundle(parent);\n            let (node_ref, braw) = self.attach(root, parent_scope, parent, slot);\n            *bundle = braw;\n            node_ref\n        } else {\n            bundle.position(slot)\n        }\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::{DynamicDomSlot, Fragment, Hydratable};\n    use crate::virtual_dom::Collectable;\n\n    impl Hydratable for VRaw {\n        fn hydrate(\n            self,\n            _root: &BSubtree,\n            _parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            let collectable = Collectable::Raw;\n            let fallback_fragment = Fragment::collect_between(fragment, &collectable, parent);\n            let first_child = fallback_fragment.iter().next().cloned();\n\n            if let (Some(first_child), prev_next_sibling) = (&first_child, prev_next_sibling) {\n                if let Some(prev_next_sibling) = prev_next_sibling {\n                    prev_next_sibling.reassign(DomSlot::at(first_child.clone()));\n                }\n                *prev_next_sibling = None;\n            }\n\n            let Self { html } = self;\n\n            BRaw {\n                children_count: fallback_fragment.len(),\n                reference: first_child,\n                html,\n            }\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod tests {\n    use gloo::utils::document;\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use super::*;\n    use crate::dom_bundle::utils::{\n        setup_parent, setup_parent_and_sibling, setup_parent_svg, SIBLING_CONTENT,\n    };\n    use crate::virtual_dom::VNode;\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn braw_works_one_node() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str = \"<span>text</span>\";\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n    }\n\n    #[test]\n    fn braw_works_svg() {\n        let (root, scope, parent) = setup_parent_svg();\n\n        const HTML: &str = r#\"<circle cx=\"50\" cy=\"50\" r=\"40\"></circle>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n        assert_eq!(\n            parent\n                .first_child()\n                .unwrap()\n                .unchecked_into::<Element>()\n                .namespace_uri(),\n            Some(SVG_NAMESPACE.to_owned())\n        );\n    }\n\n    #[test]\n    fn braw_works_no_node() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str = \"\";\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML)\n    }\n\n    #[test]\n    fn braw_works_one_node_nested() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str =\n            r#\"<p>one <a href=\"https://yew.rs\">link</a> more paragraph</p><div>here</div>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML)\n    }\n    #[test]\n    fn braw_works_multi_top_nodes() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str = r#\"<p>paragraph</p><a href=\"https://yew.rs\">link</a>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML)\n    }\n\n    #[test]\n    fn braw_detach_works_multi_node() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str = r#\"<p>paragraph</p><a href=\"https://yew.rs\">link</a>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n        elem.detach(&root, &parent, false);\n        assert_eq!(parent.inner_html(), \"\");\n    }\n\n    #[test]\n    fn braw_detach_works_single_node() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str = r#\"<p>paragraph</p>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n        elem.detach(&root, &parent, false);\n        assert_eq!(parent.inner_html(), \"\");\n    }\n\n    #[test]\n    fn braw_detach_works_empty() {\n        let (root, scope, parent) = setup_parent();\n\n        const HTML: &str = \"\";\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n        elem.detach(&root, &parent, false);\n        assert_eq!(parent.inner_html(), \"\");\n    }\n\n    #[test]\n    fn braw_works_one_node_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str = \"<span>text</span>\";\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n    }\n\n    #[test]\n    fn braw_works_no_node_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str = \"\";\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n    }\n\n    #[test]\n    fn braw_works_one_node_nested_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str =\n            r#\"<p>one <a href=\"https://yew.rs\">link</a> more paragraph</p><div>here</div>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n    }\n    #[test]\n    fn braw_works_multi_top_nodes_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str = r#\"<p>paragraph</p><a href=\"https://yew.rs\">link</a>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n    }\n\n    #[test]\n    fn braw_detach_works_multi_node_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str = r#\"<p>paragraph</p><a href=\"https://yew.rs\">link</a>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n        elem.detach(&root, &parent, false);\n        assert_eq!(parent.inner_html(), format!(\"{}\", SIBLING_CONTENT))\n    }\n\n    #[test]\n    fn braw_detach_works_single_node_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str = r#\"<p>paragraph</p>\"#;\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n        elem.detach(&root, &parent, false);\n        assert_eq!(parent.inner_html(), format!(\"{}\", SIBLING_CONTENT))\n    }\n\n    #[test]\n    fn braw_detach_works_empty_sibling_attached() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n\n        const HTML: &str = \"\";\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n        elem.detach(&root, &parent, false);\n        assert_eq!(parent.inner_html(), format!(\"{}\", SIBLING_CONTENT))\n    }\n\n    #[test]\n    fn braw_shift_works() {\n        let (root, scope, parent) = setup_parent();\n        const HTML: &str = r#\"<p>paragraph</p>\"#;\n\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n\n        let new_parent = document().create_element(\"section\").unwrap();\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        elem.shift(&new_parent, DomSlot::at_end());\n\n        assert_eq!(new_parent.inner_html(), HTML);\n        assert_eq!(parent.inner_html(), \"\");\n    }\n\n    #[test]\n    fn braw_shift_with_sibling_works() {\n        let (root, scope, parent, sibling) = setup_parent_and_sibling();\n        const HTML: &str = r#\"<p>paragraph</p>\"#;\n\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, sibling);\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), format!(\"{}{}\", HTML, SIBLING_CONTENT));\n\n        let new_parent = document().create_element(\"section\").unwrap();\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        let new_sibling = document().create_text_node(SIBLING_CONTENT);\n        new_parent.append_child(&new_sibling).unwrap();\n        let new_sibling_ref = DomSlot::at(new_sibling.into());\n\n        elem.shift(&new_parent, new_sibling_ref);\n\n        assert_eq!(parent.inner_html(), SIBLING_CONTENT);\n\n        assert_eq!(\n            new_parent.inner_html(),\n            format!(\"{}{}\", HTML, SIBLING_CONTENT)\n        );\n    }\n\n    #[test]\n    fn braw_shift_works_multi_node() {\n        let (root, scope, parent) = setup_parent();\n        const HTML: &str = r#\"<p>paragraph</p><a href=\"https://yew.rs\">link</a>\"#;\n\n        let elem = VNode::from_html_unchecked(HTML.into());\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_braw(&mut elem);\n        assert_eq!(parent.inner_html(), HTML);\n\n        let new_parent = document().create_element(\"section\").unwrap();\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        elem.shift(&new_parent, DomSlot::at_end());\n\n        assert_eq!(parent.inner_html(), \"\");\n        assert_eq!(new_parent.inner_html(), HTML);\n    }\n\n    fn assert_braw(node: &mut BNode) -> &mut BRaw {\n        if let BNode::Raw(braw) = node {\n            return braw;\n        }\n        panic!(\"should be braw\");\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/bsuspense.rs",
    "content": "//! This module contains the bundle version of a suspense [BSuspense]\n\nuse gloo::utils::document;\nuse web_sys::Element;\n\n#[cfg(feature = \"hydration\")]\nuse super::Fragment;\nuse super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\nuse crate::virtual_dom::{Key, VSuspense};\n\n#[derive(Debug)]\nenum Fallback {\n    /// Suspense Fallback with fallback being rendered as placeholder.\n    Bundle(BNode),\n    /// Suspense Fallback with Hydration Fragment being rendered as placeholder.\n    #[cfg(feature = \"hydration\")]\n    Fragment(Fragment),\n}\n\n/// The bundle implementation to [VSuspense]\n#[derive(Debug)]\npub(super) struct BSuspense {\n    children_bundle: BNode,\n    /// The suspense is suspended if fallback contains [Some] bundle\n    fallback: Option<Fallback>,\n    detached_parent: Element,\n    key: Option<Key>,\n}\n\nimpl BSuspense {\n    /// Get the key of the underlying suspense\n    pub fn key(&self) -> Option<&Key> {\n        self.key.as_ref()\n    }\n}\n\nimpl ReconcileTarget for BSuspense {\n    fn detach(self, root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        match self.fallback {\n            Some(m) => {\n                match m {\n                    Fallback::Bundle(bundle) => {\n                        bundle.detach(root, parent, parent_to_detach);\n                    }\n\n                    #[cfg(feature = \"hydration\")]\n                    Fallback::Fragment(fragment) => {\n                        fragment.detach(root, parent, parent_to_detach);\n                    }\n                }\n\n                self.children_bundle\n                    .detach(root, &self.detached_parent, false);\n            }\n            None => {\n                self.children_bundle.detach(root, parent, parent_to_detach);\n            }\n        }\n    }\n\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        match self.fallback.as_ref() {\n            Some(Fallback::Bundle(bundle)) => bundle.shift(next_parent, slot),\n            #[cfg(feature = \"hydration\")]\n            Some(Fallback::Fragment(fragment)) => fragment.shift(next_parent, slot),\n            None => self.children_bundle.shift(next_parent, slot),\n        }\n    }\n}\n\nimpl Reconcilable for VSuspense {\n    type Bundle = BSuspense;\n\n    fn attach(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let VSuspense {\n            children,\n            fallback,\n            suspended,\n            key,\n        } = self;\n        let detached_parent = document()\n            .create_element(\"div\")\n            .expect(\"failed to create detached element\");\n\n        // When it's suspended, we render children into an element that is detached from the dom\n        // tree while rendering fallback UI into the original place where children resides in.\n        if suspended {\n            let (_child_ref, children_bundle) =\n                children.attach(root, parent_scope, &detached_parent, DomSlot::at_end());\n            let (fallback_ref, fallback) = fallback.attach(root, parent_scope, parent, slot);\n            (\n                fallback_ref,\n                BSuspense {\n                    children_bundle,\n                    fallback: Some(Fallback::Bundle(fallback)),\n                    detached_parent,\n                    key,\n                },\n            )\n        } else {\n            let (child_ref, children_bundle) = children.attach(root, parent_scope, parent, slot);\n            (\n                child_ref,\n                BSuspense {\n                    children_bundle,\n                    fallback: None,\n                    detached_parent,\n                    key,\n                },\n            )\n        }\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        match bundle {\n            // We only preserve the child state if they are the same suspense.\n            BNode::Suspense(m) if m.key == self.key => {\n                self.reconcile(root, parent_scope, parent, slot, m)\n            }\n            _ => self.replace(root, parent_scope, parent, slot, bundle),\n        }\n    }\n\n    fn reconcile(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        suspense: &mut Self::Bundle,\n    ) -> DomSlot {\n        let VSuspense {\n            children,\n            fallback: vfallback,\n            suspended,\n            key: _,\n        } = self;\n\n        let children_bundle = &mut suspense.children_bundle;\n        // no need to update key & detached_parent\n\n        // When it's suspended, we render children into an element that is detached from the dom\n        // tree while rendering fallback UI into the original place where children resides in.\n        match (suspended, &mut suspense.fallback) {\n            // Both suspended, reconcile children into detached_parent, fallback into the DOM\n            (true, Some(fallback)) => {\n                children.reconcile_node(\n                    root,\n                    parent_scope,\n                    &suspense.detached_parent,\n                    DomSlot::at_end(),\n                    children_bundle,\n                );\n\n                match fallback {\n                    Fallback::Bundle(bundle) => {\n                        vfallback.reconcile_node(root, parent_scope, parent, slot, bundle)\n                    }\n                    #[cfg(feature = \"hydration\")]\n                    Fallback::Fragment(fragment) => match fragment.front().cloned() {\n                        Some(m) => DomSlot::at(m),\n                        None => slot,\n                    },\n                }\n            }\n            // Not suspended, just reconcile the children into the DOM\n            (false, None) => {\n                children.reconcile_node(root, parent_scope, parent, slot, children_bundle)\n            }\n            // Freshly suspended. Shift children into the detached parent, then add fallback to the\n            // DOM\n            (true, None) => {\n                children_bundle.shift(&suspense.detached_parent, DomSlot::at_end());\n\n                children.reconcile_node(\n                    root,\n                    parent_scope,\n                    &suspense.detached_parent,\n                    DomSlot::at_end(),\n                    children_bundle,\n                );\n                // first render of fallback\n\n                let (fallback_ref, fallback) = vfallback.attach(root, parent_scope, parent, slot);\n                suspense.fallback = Some(Fallback::Bundle(fallback));\n                fallback_ref\n            }\n            // Freshly unsuspended. Detach fallback from the DOM, then shift children into it.\n            (false, Some(_)) => {\n                match suspense.fallback.take() {\n                    Some(Fallback::Bundle(bundle)) => {\n                        bundle.detach(root, parent, false);\n                    }\n                    #[cfg(feature = \"hydration\")]\n                    Some(Fallback::Fragment(fragment)) => {\n                        fragment.detach(root, parent, false);\n                    }\n                    None => {\n                        unreachable!(\"None condition has been checked before.\")\n                    }\n                };\n\n                children_bundle.shift(parent, slot.clone());\n                children.reconcile_node(root, parent_scope, parent, slot, children_bundle)\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::{DynamicDomSlot, Fragment, Hydratable};\n    use crate::virtual_dom::Collectable;\n\n    impl Hydratable for VSuspense {\n        fn hydrate(\n            self,\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            previous_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            let detached_parent = document()\n                .create_element(\"div\")\n                .expect(\"failed to create detached element\");\n\n            let collectable = Collectable::Suspense;\n            let fallback_fragment = Fragment::collect_between(fragment, &collectable, parent);\n\n            let mut nodes = fallback_fragment.deep_clone();\n\n            for node in nodes.iter() {\n                detached_parent.append_child(node).unwrap();\n            }\n\n            // Even if initially suspended, these children correspond to the first non-suspended\n            // content Refer to VSuspense::render_to_string\n            let children_bundle = self.children.hydrate(\n                root,\n                parent_scope,\n                &detached_parent,\n                &mut nodes,\n                previous_next_sibling,\n            );\n\n            // We trim all leading text nodes before checking as it's likely these are whitespaces.\n            nodes.trim_start_text_nodes();\n\n            assert!(nodes.is_empty(), \"expected end of suspense, found node.\");\n\n            BSuspense {\n                children_bundle,\n                detached_parent,\n                key: self.key,\n\n                // We start hydration with the BSuspense being suspended.\n                // A subsequent render will resume the BSuspense if not needed to be suspended.\n                fallback: Some(Fallback::Fragment(fallback_fragment)),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/btag/attributes.rs",
    "content": "use std::collections::HashMap;\nuse std::ops::Deref;\n\nuse indexmap::IndexMap;\nuse wasm_bindgen::{intern, JsValue};\nuse web_sys::{Element, HtmlInputElement as InputElement, HtmlTextAreaElement as TextAreaElement};\nuse yew::AttrValue;\n\nuse super::Apply;\nuse crate::dom_bundle::BSubtree;\nuse crate::virtual_dom::vtag::{InputFields, TextareaFields, Value};\nuse crate::virtual_dom::{AttributeOrProperty, Attributes};\n\nimpl<T: AccessValue> Apply for Value<T> {\n    type Bundle = Self;\n    type Element = T;\n\n    fn apply(self, _root: &BSubtree, el: &Self::Element) -> Self {\n        if let Some(v) = self.deref() {\n            el.set_value(v);\n        }\n        self\n    }\n\n    fn apply_diff(self, _root: &BSubtree, el: &Self::Element, bundle: &mut Self) {\n        match (self.deref(), (*bundle).deref()) {\n            (Some(new), Some(_)) => {\n                // Refresh value from the DOM. It might have changed.\n                if new.as_ref() != el.value() {\n                    el.set_value(new);\n                }\n            }\n            (Some(new), None) => el.set_value(new),\n            (None, Some(_)) => el.set_value(\"\"),\n            (None, None) => (),\n        }\n    }\n}\n\nmacro_rules! impl_access_value {\n    ($( $type:ty )*) => {\n        $(\n            impl AccessValue for $type {\n                #[inline]\n                fn value(&self) -> String {\n                    <$type>::value(&self)\n                }\n\n                #[inline]\n                fn set_value(&self, v: &str) {\n                    <$type>::set_value(&self, v)\n                }\n            }\n        )*\n    };\n}\nimpl_access_value! {InputElement TextAreaElement}\n\n/// Able to have its value read or set\npub(super) trait AccessValue {\n    fn value(&self) -> String;\n    fn set_value(&self, v: &str);\n}\n\nimpl Apply for InputFields {\n    type Bundle = Self;\n    type Element = InputElement;\n\n    fn apply(mut self, root: &BSubtree, el: &Self::Element) -> Self {\n        // IMPORTANT! This parameter has to be set every time it's explicitly given\n        // to prevent strange behaviour in the browser when the DOM changes\n        if let Some(checked) = self.checked {\n            el.set_checked(checked);\n        }\n\n        self.value = self.value.apply(root, el);\n        self\n    }\n\n    fn apply_diff(self, root: &BSubtree, el: &Self::Element, bundle: &mut Self) {\n        // IMPORTANT! This parameter has to be set every time it's explicitly given\n        // to prevent strange behaviour in the browser when the DOM changes\n        if let Some(checked) = self.checked {\n            el.set_checked(checked);\n        }\n\n        self.value.apply_diff(root, el, &mut bundle.value);\n    }\n}\n\nimpl Apply for TextareaFields {\n    type Bundle = Value<TextAreaElement>;\n    type Element = TextAreaElement;\n\n    fn apply(self, root: &BSubtree, el: &Self::Element) -> Self::Bundle {\n        if let Some(def) = self.defaultvalue {\n            _ = el.set_default_value(def.as_str());\n        }\n        self.value.apply(root, el)\n    }\n\n    fn apply_diff(self, root: &BSubtree, el: &Self::Element, bundle: &mut Self::Bundle) {\n        self.value.apply_diff(root, el, bundle)\n    }\n}\n\nimpl Attributes {\n    #[cold]\n    fn apply_diff_index_maps(\n        el: &Element,\n        new: &IndexMap<AttrValue, AttributeOrProperty>,\n        old: &IndexMap<AttrValue, AttributeOrProperty>,\n    ) {\n        for (key, value) in new.iter() {\n            match old.get(key) {\n                Some(old_value) => {\n                    if value != old_value {\n                        Self::set(el, key, value);\n                    }\n                }\n                None => Self::set(el, key, value),\n            }\n        }\n\n        for (key, value) in old.iter() {\n            if !new.contains_key(key) {\n                Self::remove(el, key, value);\n            }\n        }\n    }\n\n    /// Convert [Attributes] pair to [HashMap]s and patch changes to `el`.\n    /// Works with any [Attributes] variants.\n    #[cold]\n    fn apply_diff_as_maps<'a>(el: &Element, new: &'a Self, old: &'a Self) {\n        fn collect(src: &Attributes) -> HashMap<&str, &AttributeOrProperty> {\n            use Attributes::*;\n\n            match src {\n                Static(arr) => (*arr).iter().map(|(k, v)| (*k, v)).collect(),\n                Dynamic { keys, values } => keys\n                    .iter()\n                    .zip(values.iter())\n                    .filter_map(|(k, v)| v.as_ref().map(|v| (*k, v)))\n                    .collect(),\n                IndexMap(m) => m.iter().map(|(k, v)| (k.as_ref(), v)).collect(),\n            }\n        }\n\n        let new = collect(new);\n        let old = collect(old);\n\n        // Update existing or set new\n        for (k, new) in new.iter() {\n            if match old.get(k) {\n                Some(old) => old != new,\n                None => true,\n            } {\n                Self::set(el, k, new);\n            }\n        }\n\n        // Remove missing\n        for (k, old_value) in old.iter() {\n            if !new.contains_key(k) {\n                Self::remove(el, k, old_value);\n            }\n        }\n    }\n\n    fn set(el: &Element, key: &str, value: &AttributeOrProperty) {\n        match value {\n            AttributeOrProperty::Attribute(value) => el\n                .set_attribute(intern(key), value)\n                .expect(\"invalid attribute key\"),\n            AttributeOrProperty::Static(value) => el\n                .set_attribute(intern(key), value)\n                .expect(\"invalid attribute key\"),\n            AttributeOrProperty::Property(value) => {\n                let key = JsValue::from_str(key);\n                js_sys::Reflect::set(el.as_ref(), &key, value).expect(\"could not set property\");\n            }\n        }\n    }\n\n    fn remove(el: &Element, key: &str, old_value: &AttributeOrProperty) {\n        match old_value {\n            AttributeOrProperty::Attribute(_) | AttributeOrProperty::Static(_) => el\n                .remove_attribute(intern(key))\n                .expect(\"could not remove attribute\"),\n            AttributeOrProperty::Property(_) => {\n                let key = JsValue::from_str(key);\n                js_sys::Reflect::set(el.as_ref(), &key, &JsValue::UNDEFINED)\n                    .expect(\"could not remove property\");\n            }\n        }\n    }\n}\n\nimpl Apply for Attributes {\n    type Bundle = Self;\n    type Element = Element;\n\n    fn apply(self, _root: &BSubtree, el: &Element) -> Self {\n        match &self {\n            Self::Static(arr) => {\n                for (k, v) in arr.iter() {\n                    Self::set(el, k, v);\n                }\n            }\n            Self::Dynamic { keys, values } => {\n                for (k, v) in keys.iter().zip(values.iter()) {\n                    if let Some(v) = v {\n                        Self::set(el, k, v)\n                    }\n                }\n            }\n            Self::IndexMap(m) => {\n                for (k, v) in m.iter() {\n                    Self::set(el, k, v)\n                }\n            }\n        }\n        self\n    }\n\n    fn apply_diff(self, _root: &BSubtree, el: &Element, bundle: &mut Self) {\n        #[inline]\n        fn ptr_eq<T>(a: &[T], b: &[T]) -> bool {\n            std::ptr::eq(a, b)\n        }\n\n        let ancestor = std::mem::replace(bundle, self);\n        let bundle = &*bundle; // reborrow it immutably from here\n        match (bundle, ancestor) {\n            // Hot path\n            (Self::Static(new), Self::Static(old)) if ptr_eq(new, old) => (),\n            // Hot path\n            (\n                Self::Dynamic {\n                    keys: new_k,\n                    values: new_v,\n                },\n                Self::Dynamic {\n                    keys: old_k,\n                    values: old_v,\n                },\n            ) if ptr_eq(new_k, old_k) => {\n                // Double zipping does not optimize well, so use asserts and unsafe instead\n                assert_eq!(new_k.len(), new_v.len());\n                assert_eq!(new_k.len(), old_v.len());\n                for i in 0..new_k.len() {\n                    macro_rules! key {\n                        () => {\n                            unsafe { new_k.get_unchecked(i) }\n                        };\n                    }\n                    macro_rules! set {\n                        ($new:expr) => {\n                            Self::set(el, key!(), $new)\n                        };\n                    }\n\n                    match unsafe { (new_v.get_unchecked(i), old_v.get_unchecked(i)) } {\n                        (Some(new), Some(old)) => {\n                            if new != old {\n                                set!(new);\n                            }\n                        }\n                        (Some(new), None) => set!(new),\n                        (None, Some(old)) => {\n                            Self::remove(el, key!(), old);\n                        }\n                        (None, None) => (),\n                    }\n                }\n            }\n            // For VTag's constructed outside the html! macro\n            (Self::IndexMap(new), Self::IndexMap(ref old)) => {\n                Self::apply_diff_index_maps(el, new, old);\n            }\n            // Cold path. Happens only with conditional swapping and reordering of `VTag`s with the\n            // same tag and no keys.\n            (new, ref ancestor) => {\n                Self::apply_diff_as_maps(el, new, ancestor);\n            }\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod tests {\n    use std::rc::Rc;\n    use std::time::Duration;\n\n    use gloo::utils::document;\n    use js_sys::Reflect;\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use super::*;\n    use crate::{component, html, Html};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    fn create_element() -> (Element, BSubtree) {\n        let element = document()\n            .create_element(\"a\")\n            .expect(\"failed to create element\");\n        let btree = BSubtree::create_root(&element);\n        (element, btree)\n    }\n\n    #[test]\n    fn properties_are_set() {\n        let attrs = indexmap::indexmap! {\n            AttrValue::Static(\"href\") => AttributeOrProperty::Property(JsValue::from_str(\"https://example.com/\")),\n            AttrValue::Static(\"alt\") => AttributeOrProperty::Property(JsValue::from_str(\"somewhere\")),\n        };\n        let attrs = Attributes::IndexMap(Rc::new(attrs));\n        let (element, btree) = create_element();\n        attrs.apply(&btree, &element);\n        assert_eq!(\n            Reflect::get(element.as_ref(), &JsValue::from_str(\"href\"))\n                .expect(\"no href\")\n                .as_string()\n                .expect(\"not a string\"),\n            \"https://example.com/\",\n            \"property `href` not set properly\"\n        );\n        assert_eq!(\n            Reflect::get(element.as_ref(), &JsValue::from_str(\"alt\"))\n                .expect(\"no alt\")\n                .as_string()\n                .expect(\"not a string\"),\n            \"somewhere\",\n            \"property `alt` not set properly\"\n        );\n    }\n\n    #[test]\n    fn respects_apply_as() {\n        let attrs = indexmap::indexmap! {\n            AttrValue::Static(\"href\") => AttributeOrProperty::Attribute(AttrValue::from(\"https://example.com/\")),\n            AttrValue::Static(\"alt\") => AttributeOrProperty::Property(JsValue::from_str(\"somewhere\")),\n        };\n        let attrs = Attributes::IndexMap(Rc::new(attrs));\n        let (element, btree) = create_element();\n        attrs.apply(&btree, &element);\n        assert_eq!(\n            element.outer_html(),\n            \"<a href=\\\"https://example.com/\\\"></a>\",\n            \"should be set as attribute\"\n        );\n        assert_eq!(\n            Reflect::get(element.as_ref(), &JsValue::from_str(\"alt\"))\n                .expect(\"no alt\")\n                .as_string()\n                .expect(\"not a string\"),\n            \"somewhere\",\n            \"property `alt` not set properly\"\n        );\n    }\n\n    #[test]\n    fn class_is_always_attrs() {\n        let attrs = Attributes::Static(&[(\"class\", AttributeOrProperty::Static(\"thing\"))]);\n\n        let (element, btree) = create_element();\n        attrs.apply(&btree, &element);\n        assert_eq!(element.get_attribute(\"class\").unwrap(), \"thing\");\n    }\n\n    #[test]\n    async fn macro_syntax_works() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <a href=\"https://example.com/\" ~alt={\"abc\"} ~data-bool={JsValue::from_bool(true)} /> }\n        }\n\n        let output = document().get_element_by_id(\"output\").unwrap();\n        yew::Renderer::<Comp>::with_root(output.clone()).render();\n\n        gloo::timers::future::sleep(Duration::from_secs(1)).await;\n        let element = output.query_selector(\"a\").unwrap().unwrap();\n        assert_eq!(\n            element.get_attribute(\"href\").unwrap(),\n            \"https://example.com/\"\n        );\n\n        assert_eq!(\n            Reflect::get(element.as_ref(), &JsValue::from_str(\"alt\"))\n                .expect(\"no alt\")\n                .as_string()\n                .expect(\"not a string\"),\n            \"abc\",\n            \"property `alt` not set properly\"\n        );\n\n        assert!(\n            Reflect::get(element.as_ref(), &JsValue::from_str(\"data-bool\"))\n                .expect(\"no alt\")\n                .as_bool()\n                .expect(\"not a bool\"),\n            \"property `alt` not set properly\"\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/btag/listeners.rs",
    "content": "use std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse wasm_bindgen::prelude::wasm_bindgen;\nuse wasm_bindgen::JsCast;\nuse web_sys::{Element, Event, EventTarget as HtmlEventTarget};\n\nuse super::Apply;\nuse crate::dom_bundle::{test_log, BSubtree, EventDescriptor};\nuse crate::virtual_dom::{Listener, Listeners};\n\n#[wasm_bindgen]\nextern \"C\" {\n    // Duck-typing, not a real class on js-side. On rust-side, use impls of EventTarget below\n    type EventTargetable;\n    #[wasm_bindgen(method, getter = __yew_listener_id, structural)]\n    fn listener_id(this: &EventTargetable) -> Option<u32>;\n    #[wasm_bindgen(method, setter = __yew_listener_id, structural)]\n    fn set_listener_id(this: &EventTargetable, id: u32);\n}\n\n/// DOM-Types that can have listeners registered on them.\n/// Uses the duck-typed interface from above in impls.\npub trait EventListening {\n    fn listener_id(&self) -> Option<u32>;\n    fn set_listener_id(&self, id: u32);\n}\n\nimpl EventListening for Element {\n    fn listener_id(&self) -> Option<u32> {\n        self.unchecked_ref::<EventTargetable>().listener_id()\n    }\n\n    fn set_listener_id(&self, id: u32) {\n        self.unchecked_ref::<EventTargetable>().set_listener_id(id);\n    }\n}\n\n/// An active set of listeners on an element\n#[derive(Debug)]\npub(super) enum ListenerRegistration {\n    /// No listeners registered.\n    NoReg,\n    /// Added to global registry by ID\n    Registered(u32),\n}\n\nimpl Apply for Listeners {\n    type Bundle = ListenerRegistration;\n    type Element = Element;\n\n    fn apply(self, root: &BSubtree, el: &Self::Element) -> ListenerRegistration {\n        match self {\n            Self::Pending(pending) => ListenerRegistration::register(root, el, &pending),\n            Self::None => ListenerRegistration::NoReg,\n        }\n    }\n\n    fn apply_diff(self, root: &BSubtree, el: &Self::Element, bundle: &mut ListenerRegistration) {\n        use ListenerRegistration::*;\n        use Listeners::*;\n\n        match (self, bundle) {\n            (Pending(pending), Registered(ref id)) => {\n                // Reuse the ID\n                test_log!(\"reusing listeners for {}\", id);\n                root.with_listener_registry(|reg| reg.patch(root, id, &pending));\n            }\n            (Pending(pending), bundle @ NoReg) => {\n                *bundle = ListenerRegistration::register(root, el, &pending);\n                test_log!(\n                    \"registering listeners for {}\",\n                    match bundle {\n                        ListenerRegistration::Registered(id) => id,\n                        _ => unreachable!(),\n                    }\n                );\n            }\n            (None, bundle @ Registered(_)) => {\n                let id = match bundle {\n                    ListenerRegistration::Registered(ref id) => id,\n                    _ => unreachable!(),\n                };\n                test_log!(\"unregistering listeners for {}\", id);\n                root.with_listener_registry(|reg| reg.unregister(id));\n                *bundle = NoReg;\n            }\n            (None, NoReg) => {\n                test_log!(\"{}\", &\"unchanged empty listeners\");\n            }\n        };\n    }\n}\n\nimpl ListenerRegistration {\n    /// Register listeners and return their handle ID\n    fn register(root: &BSubtree, el: &Element, pending: &[Option<Rc<dyn Listener>>]) -> Self {\n        Self::Registered(root.with_listener_registry(|reg| {\n            let id = reg.set_listener_id(root, el);\n            reg.register(root, id, pending);\n            id\n        }))\n    }\n\n    /// Remove any registered event listeners from the global registry\n    pub fn unregister(&self, root: &BSubtree) {\n        if let Self::Registered(id) = self {\n            root.with_listener_registry(|r| r.unregister(id));\n        }\n    }\n}\n\n/// Global multiplexing event handler registry\n#[derive(Debug)]\npub struct Registry {\n    /// Counter for assigning new IDs\n    id_counter: u32,\n\n    /// Contains all registered event listeners by listener ID\n    by_id: HashMap<u32, HashMap<EventDescriptor, Vec<Rc<dyn Listener>>>>,\n}\n\nimpl Registry {\n    pub fn new() -> Self {\n        Self {\n            id_counter: u32::default(),\n            by_id: HashMap::default(),\n        }\n    }\n\n    /// Handle a single event, given the listening element and event descriptor.\n    pub fn get_handler(\n        registry: &RefCell<Registry>,\n        listening: &dyn EventListening,\n        desc: &EventDescriptor,\n    ) -> Option<impl FnOnce(&Event)> {\n        // The tricky part is that we want to drop the reference to the registry before\n        // calling any actual listeners (since that might end up running lifecycle methods\n        // and modify the registry). So we clone the current listeners and return a closure\n        let listener_id = listening.listener_id()?;\n        let registry_ref = registry.borrow();\n        let handlers = registry_ref.by_id.get(&listener_id)?;\n        let listeners = handlers.get(desc)?.clone();\n        drop(registry_ref); // unborrow the registry, before running any listeners\n        Some(move |event: &Event| {\n            for l in listeners {\n                l.handle(event.clone());\n            }\n        })\n    }\n\n    /// Register all passed listeners under ID\n    fn register(&mut self, root: &BSubtree, id: u32, listeners: &[Option<Rc<dyn Listener>>]) {\n        let mut by_desc =\n            HashMap::<EventDescriptor, Vec<Rc<dyn Listener>>>::with_capacity(listeners.len());\n        for l in listeners.iter().filter_map(|l| l.as_ref()).cloned() {\n            let desc = EventDescriptor::from(l.deref());\n            root.ensure_handled(&desc);\n            by_desc.entry(desc).or_default().push(l);\n        }\n        self.by_id.insert(id, by_desc);\n    }\n\n    /// Patch an already registered set of handlers\n    fn patch(&mut self, root: &BSubtree, id: &u32, listeners: &[Option<Rc<dyn Listener>>]) {\n        if let Some(by_desc) = self.by_id.get_mut(id) {\n            // Keeping empty vectors is fine. Those don't do much and should happen rarely.\n            for v in by_desc.values_mut() {\n                v.clear()\n            }\n\n            for l in listeners.iter().filter_map(|l| l.as_ref()).cloned() {\n                let desc = EventDescriptor::from(l.deref());\n                root.ensure_handled(&desc);\n                by_desc.entry(desc).or_default().push(l);\n            }\n        }\n    }\n\n    /// Unregister any existing listeners for ID\n    fn unregister(&mut self, id: &u32) {\n        self.by_id.remove(id);\n    }\n\n    /// Set unique listener ID onto element and return it\n    fn set_listener_id(&mut self, root: &BSubtree, el: &Element) -> u32 {\n        let id = self.id_counter;\n        self.id_counter += 1;\n\n        root.brand_element(el as &HtmlEventTarget);\n        el.set_listener_id(id);\n\n        id\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod tests {\n    use std::marker::PhantomData;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n    use web_sys::{Event, EventInit, FocusEvent, HtmlElement, MouseEvent};\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    use gloo::utils::document;\n    use wasm_bindgen::JsCast;\n    use yew::Callback;\n\n    use crate::html::TargetCast;\n    use crate::virtual_dom::VNode;\n    use crate::{\n        create_portal, html, scheduler, AppHandle, Component, Context, Html, NodeRef, Properties,\n    };\n\n    #[derive(Clone)]\n    enum Message {\n        Action,\n        StopListening,\n        SetText(String),\n    }\n\n    #[derive(Default)]\n    struct State {\n        stop_listening: bool,\n        action: u32,\n        text: String,\n    }\n\n    #[derive(Default, PartialEq, Properties)]\n    struct MixinProps<M: Properties> {\n        state_ref: NodeRef,\n        wrapped: M,\n    }\n\n    trait Mixin: Properties + Sized {\n        fn view<C>(ctx: &Context<C>, state: &State) -> Html\n        where\n            C: Component<Message = Message, Properties = MixinProps<Self>>;\n    }\n\n    struct Comp<M>\n    where\n        M: Mixin + 'static,\n    {\n        state: State,\n        pd: PhantomData<M>,\n    }\n\n    impl<M> Component for Comp<M>\n    where\n        M: Mixin + Properties + 'static,\n    {\n        type Message = Message;\n        type Properties = MixinProps<M>;\n\n        fn create(_: &Context<Self>) -> Self {\n            Comp {\n                state: Default::default(),\n                pd: PhantomData,\n            }\n        }\n\n        fn update(&mut self, _: &Context<Self>, msg: Self::Message) -> bool {\n            match msg {\n                Message::Action => {\n                    self.state.action += 1;\n                }\n                Message::StopListening => {\n                    self.state.stop_listening = true;\n                }\n                Message::SetText(s) => {\n                    self.state.text = s;\n                }\n            };\n            true\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> crate::Html {\n            M::view(ctx, &self.state)\n        }\n    }\n\n    #[track_caller]\n    fn assert_count(el: &NodeRef, count: isize) {\n        let text = el\n            .get()\n            .expect(\"State ref not bound in the test case?\")\n            .text_content();\n        assert_eq!(text, Some(count.to_string()))\n    }\n\n    #[track_caller]\n    fn click(el: &NodeRef) {\n        el.get().unwrap().dyn_into::<HtmlElement>().unwrap().click();\n        scheduler::start_now();\n    }\n\n    fn get_el_by_selector(selector: &str) -> web_sys::HtmlElement {\n        document()\n            .query_selector(selector)\n            .unwrap()\n            .unwrap()\n            .dyn_into::<web_sys::HtmlElement>()\n            .unwrap()\n    }\n\n    fn init<M>() -> (AppHandle<Comp<M>>, NodeRef)\n    where\n        M: Mixin + Properties + Default,\n    {\n        // Remove any existing elements\n        let body = document().query_selector(\"#output\").unwrap().unwrap();\n        while let Some(child) = body.query_selector(\"div#testroot\").unwrap() {\n            body.remove_child(&child).unwrap();\n        }\n\n        let root = document().create_element(\"div\").unwrap();\n        root.set_id(\"testroot\");\n        body.append_child(&root).unwrap();\n        let props = <Comp<M> as Component>::Properties::default();\n        let el_ref = props.state_ref.clone();\n        let app = crate::Renderer::<Comp<M>>::with_root_and_props(root, props).render();\n        scheduler::start_now();\n\n        (app, el_ref)\n    }\n\n    #[test]\n    fn synchronous() {\n        #[derive(Default, PartialEq, Properties)]\n        struct Synchronous;\n\n        impl Mixin for Synchronous {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let onclick = ctx.link().callback(|_| Message::Action);\n\n                if state.stop_listening {\n                    html! {\n                        <a ref={&ctx.props().state_ref}>{state.action}</a>\n                    }\n                } else {\n                    html! {\n                        <a {onclick} ref={&ctx.props().state_ref}>\n                            {state.action}\n                        </a>\n                    }\n                }\n            }\n        }\n\n        let (link, el) = init::<Synchronous>();\n\n        assert_count(&el, 0);\n\n        click(&el);\n        assert_count(&el, 1);\n\n        click(&el);\n        assert_count(&el, 2);\n\n        link.send_message(Message::StopListening);\n        scheduler::start_now();\n\n        click(&el);\n        assert_count(&el, 2);\n    }\n\n    #[test]\n    async fn non_bubbling_event() {\n        #[derive(Default, PartialEq, Properties)]\n        struct NonBubbling;\n\n        impl Mixin for NonBubbling {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let link = ctx.link().clone();\n                let onblur = Callback::from(move |_| {\n                    link.send_message(Message::Action);\n                    scheduler::start_now();\n                });\n                html! {\n                    <div>\n                        <a ref={&ctx.props().state_ref}>\n                            <input id=\"input\" {onblur} type=\"text\" />\n                            {state.action}\n                        </a>\n                    </div>\n                }\n            }\n        }\n\n        let (_, el) = init::<NonBubbling>();\n\n        assert_count(&el, 0);\n\n        let input = document().get_element_by_id(\"input\").unwrap();\n\n        input\n            .dispatch_event(\n                &Event::new_with_event_init_dict(\"blur\", &{\n                    let mut dict = EventInit::new();\n                    dict.bubbles(false);\n                    dict\n                })\n                .unwrap(),\n            )\n            .unwrap();\n\n        assert_count(&el, 1);\n    }\n\n    #[test]\n    fn bubbling() {\n        #[derive(Default, PartialEq, Properties)]\n        struct Bubbling;\n\n        impl Mixin for Bubbling {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                if state.stop_listening {\n                    html! {\n                        <div>\n                            <a ref={&ctx.props().state_ref}>\n                                {state.action}\n                            </a>\n                        </div>\n                    }\n                } else {\n                    let cb = ctx.link().callback(|_| Message::Action);\n                    html! {\n                        <div onclick={cb.clone()}>\n                            <a onclick={cb} ref={&ctx.props().state_ref}>\n                                {state.action}\n                            </a>\n                        </div>\n                    }\n                }\n            }\n        }\n\n        let (link, el) = init::<Bubbling>();\n\n        assert_count(&el, 0);\n        click(&el);\n        assert_count(&el, 2);\n        click(&el);\n        assert_count(&el, 4);\n\n        link.send_message(Message::StopListening);\n        scheduler::start_now();\n        click(&el);\n        assert_count(&el, 4);\n    }\n\n    #[test]\n    fn cancel_bubbling() {\n        #[derive(Default, PartialEq, Properties)]\n        struct CancelBubbling;\n\n        impl Mixin for CancelBubbling {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let onclick = ctx.link().callback(|_| Message::Action);\n                let onclick2 = ctx.link().callback(|e: MouseEvent| {\n                    e.stop_propagation();\n                    Message::Action\n                });\n\n                html! {\n                    <div onclick={onclick}>\n                        <a onclick={onclick2} ref={&ctx.props().state_ref}>\n                            {state.action}\n                        </a>\n                    </div>\n                }\n            }\n        }\n\n        let (_, el) = init::<CancelBubbling>();\n\n        assert_count(&el, 0);\n        click(&el);\n        assert_count(&el, 1);\n        click(&el);\n        assert_count(&el, 2);\n    }\n\n    #[test]\n    fn cancel_bubbling_nested() {\n        // Here an event is being delivered to a DOM node which does\n        // _not_ have a listener but which is contained within an\n        // element that does and which cancels the bubble.\n        #[derive(Default, PartialEq, Properties)]\n        struct CancelBubbling;\n\n        impl Mixin for CancelBubbling {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let onclick = ctx.link().callback(|_| Message::Action);\n                let onclick2 = ctx.link().callback(|e: MouseEvent| {\n                    e.stop_propagation();\n                    Message::Action\n                });\n                html! {\n                    <div onclick={onclick}>\n                        <div onclick={onclick2}>\n                            <a ref={&ctx.props().state_ref}>\n                                {state.action}\n                            </a>\n                        </div>\n                    </div>\n                }\n            }\n        }\n\n        let (_, el) = init::<CancelBubbling>();\n\n        assert_count(&el, 0);\n        click(&el);\n        assert_count(&el, 1);\n        click(&el);\n        assert_count(&el, 2);\n    }\n\n    #[test]\n    fn non_bubbling() {\n        #[derive(Default, PartialEq, Properties)]\n        struct NonBubbling;\n\n        impl Mixin for NonBubbling {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let onfocus = ctx.link().callback(|_| Message::Action);\n                let onfocus_inner = ctx.link().callback(|e: FocusEvent| {\n                    assert!(!e.bubbles(), \"event should be non-bubbling\");\n                    Message::Action\n                });\n\n                html! {\n                    <div {onfocus}>\n                        <button onfocus={onfocus_inner} ref={&ctx.props().state_ref}>\n                            {state.action}\n                        </button>\n                    </div>\n                }\n            }\n        }\n        // Should only trigger the inner listener, not also the outer one\n        let (_, el) = init::<NonBubbling>();\n\n        assert_count(&el, 0);\n        el.get()\n            .unwrap()\n            .dyn_into::<HtmlElement>()\n            .unwrap()\n            .focus()\n            .unwrap();\n        scheduler::start_now();\n        assert_count(&el, 1);\n    }\n\n    /// Here an event is being delivered to a DOM node which is contained\n    /// in a portal. It should bubble through the portal and reach the containing\n    /// element.\n    #[test]\n    fn portal_bubbling() {\n        #[derive(PartialEq, Properties)]\n        struct PortalBubbling {\n            host: web_sys::Element,\n        }\n        impl Default for PortalBubbling {\n            fn default() -> Self {\n                let host = document().create_element(\"div\").unwrap();\n                PortalBubbling { host }\n            }\n        }\n\n        impl Mixin for PortalBubbling {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let portal_target = ctx.props().wrapped.host.clone();\n                let onclick = ctx.link().callback(|_| Message::Action);\n                html! {\n                    <>\n                        <div onclick={onclick}>\n                            {create_portal(html! {\n                                <a ref={&ctx.props().state_ref}>\n                                    {state.action}\n                                </a>\n                            }, portal_target.clone())}\n                        </div>\n                        {VNode::VRef(portal_target.into())}\n                    </>\n                }\n            }\n        }\n\n        let (_, el) = init::<PortalBubbling>();\n\n        assert_count(&el, 0);\n        click(&el);\n        assert_count(&el, 1);\n    }\n\n    /// Here an event is being from inside a shadow root. It should only be caught exactly once on\n    /// each handler\n    #[test]\n    fn open_shadow_dom_bubbling() {\n        use web_sys::{ShadowRootInit, ShadowRootMode};\n        #[derive(PartialEq, Properties)]\n        struct OpenShadowDom {\n            host: web_sys::Element,\n            inner_root: web_sys::Element,\n        }\n        impl Default for OpenShadowDom {\n            fn default() -> Self {\n                let host = document().create_element(\"div\").unwrap();\n                let inner_root = document().create_element(\"div\").unwrap();\n                let shadow = host\n                    .attach_shadow(&ShadowRootInit::new(ShadowRootMode::Open))\n                    .unwrap();\n                shadow.append_child(&inner_root).unwrap();\n                OpenShadowDom { host, inner_root }\n            }\n        }\n        impl Mixin for OpenShadowDom {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let onclick = ctx.link().callback(|_| Message::Action);\n                let mixin = &ctx.props().wrapped;\n                html! {\n                    <div onclick={onclick.clone()}>\n                        <div {onclick}>\n                            {create_portal(html! {\n                                <a ref={&ctx.props().state_ref}>\n                                    {state.action}\n                                </a>\n                            }, mixin.inner_root.clone())}\n                        </div>\n                        {VNode::VRef(mixin.host.clone().into())}\n                    </div>\n                }\n            }\n        }\n        let (_, el) = init::<OpenShadowDom>();\n\n        assert_count(&el, 0);\n        click(&el);\n        assert_count(&el, 2); // Once caught per handler\n    }\n\n    fn test_input_listener<E>(make_event: impl Fn() -> E)\n    where\n        E: Into<Event> + std::fmt::Debug,\n    {\n        #[derive(Default, PartialEq, Properties)]\n        struct Input;\n\n        impl Mixin for Input {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                if state.stop_listening {\n                    html! {\n                        <div>\n                            <input type=\"text\" />\n                            <p ref={&ctx.props().state_ref}>{state.text.clone()}</p>\n                        </div>\n                    }\n                } else {\n                    let onchange = ctx.link().callback(|e: web_sys::Event| {\n                        let el: web_sys::HtmlInputElement = e.target_unchecked_into();\n                        Message::SetText(el.value())\n                    });\n                    let oninput = ctx.link().callback(|e: web_sys::InputEvent| {\n                        let el: web_sys::HtmlInputElement = e.target_unchecked_into();\n                        Message::SetText(el.value())\n                    });\n\n                    html! {\n                        <div>\n                            <input type=\"text\" {onchange} {oninput} />\n                            <p ref={&ctx.props().state_ref}>{state.text.clone()}</p>\n                        </div>\n                    }\n                }\n            }\n        }\n\n        let (link, state_ref) = init::<Input>();\n        let input_el = get_el_by_selector(\"input\")\n            .dyn_into::<web_sys::HtmlInputElement>()\n            .unwrap();\n\n        assert_eq!(&state_ref.get().unwrap().text_content().unwrap(), \"\");\n        for mut s in [\"foo\", \"bar\", \"baz\"].iter() {\n            input_el.set_value(s);\n            if s == &\"baz\" {\n                link.send_message(Message::StopListening);\n                scheduler::start_now();\n\n                s = &\"bar\";\n            }\n            input_el.dispatch_event(&make_event().into()).unwrap();\n            scheduler::start_now();\n            assert_eq!(&state_ref.get().unwrap().text_content().unwrap(), s);\n        }\n    }\n\n    #[test]\n    fn oninput() {\n        test_input_listener(|| {\n            web_sys::InputEvent::new_with_event_init_dict(\n                \"input\",\n                web_sys::InputEventInit::new().bubbles(true),\n            )\n            .unwrap()\n        })\n    }\n\n    #[test]\n    fn onchange() {\n        test_input_listener(|| {\n            web_sys::Event::new_with_event_init_dict(\n                \"change\",\n                web_sys::EventInit::new().bubbles(true),\n            )\n            .unwrap()\n        })\n    }\n\n    #[test]\n    fn reentrant_listener() {\n        #[derive(PartialEq, Properties, Default)]\n        struct Reetrant {\n            secondary_target_ref: NodeRef,\n        }\n        impl Mixin for Reetrant {\n            fn view<C>(ctx: &Context<C>, state: &State) -> Html\n            where\n                C: Component<Message = Message, Properties = MixinProps<Self>>,\n            {\n                let targetref = &ctx.props().wrapped.secondary_target_ref;\n                let onclick = {\n                    let targetref = targetref.clone();\n                    ctx.link().callback(move |_| {\n                        // Note: `click` (and dispatchEvent for that matter) swallows errors thrown\n                        // from listeners and reports them as uncaught to the console. Hence, we\n                        // assert that we got to the second event listener instead, by dispatching a\n                        // second Message::Action\n                        click(&targetref);\n                        Message::Action\n                    })\n                };\n                let onclick2 = ctx.link().callback(move |_| Message::Action);\n                html! {\n                    <div>\n                        <button {onclick} ref={&ctx.props().state_ref}>{state.action}</button>\n                        <a onclick={onclick2} ref={targetref}></a>\n                    </div>\n                }\n            }\n        }\n        let (_, el) = init::<Reetrant>();\n\n        assert_count(&el, 0);\n        click(&el);\n        assert_count(&el, 2);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/btag/mod.rs",
    "content": "//! This module contains the bundle implementation of a tag [BTag]\n\nmod attributes;\nmod listeners;\n\nuse std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::hint::unreachable_unchecked;\nuse std::ops::DerefMut;\n\nuse gloo::utils::document;\nuse listeners::ListenerRegistration;\npub use listeners::Registry;\nuse wasm_bindgen::JsCast;\nuse web_sys::{Element, HtmlTextAreaElement as TextAreaElement};\n\nuse super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\n#[cfg(feature = \"hydration\")]\nuse crate::virtual_dom::vtag::HTML_NAMESPACE;\nuse crate::virtual_dom::vtag::{\n    InputFields, TextareaFields, VTagInner, Value, MATHML_NAMESPACE, SVG_NAMESPACE,\n};\nuse crate::virtual_dom::{AttrValue, Attributes, Key, VTag};\nuse crate::NodeRef;\n\n/// Applies contained changes to DOM [web_sys::Element]\ntrait Apply {\n    /// [web_sys::Element] subtype to apply the changes to\n    type Element;\n    type Bundle;\n\n    /// Apply contained values to [Element](Self::Element) with no ancestor\n    fn apply(self, root: &BSubtree, el: &Self::Element) -> Self::Bundle;\n\n    /// Apply diff between [self] and `bundle` to [Element](Self::Element).\n    fn apply_diff(self, root: &BSubtree, el: &Self::Element, bundle: &mut Self::Bundle);\n}\n\n/// [BTag] fields that are specific to different [BTag] kinds.\n/// Decreases the memory footprint of [BTag] by avoiding impossible field and value combinations.\n#[derive(Debug)]\nenum BTagInner {\n    /// Fields specific to\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)\n    Input(InputFields),\n    /// Fields specific to\n    /// [TextArea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)\n    Textarea {\n        /// Contains a value of an\n        /// [TextArea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)\n        value: Value<TextAreaElement>,\n    },\n    /// Fields for all other kinds of [VTag]s\n    Other {\n        /// A tag of the element.\n        tag: AttrValue,\n        /// Child node.\n        child_bundle: BNode,\n    },\n}\n\n/// The bundle implementation to [VTag]\n#[derive(Debug)]\npub(super) struct BTag {\n    /// [BTag] fields that are specific to different [BTag] kinds.\n    inner: BTagInner,\n    listeners: ListenerRegistration,\n    attributes: Attributes,\n    /// A reference to the DOM [`Element`].\n    reference: Element,\n    /// A node reference used for DOM access in Component lifecycle methods\n    node_ref: NodeRef,\n    key: Option<Key>,\n}\n\nimpl ReconcileTarget for BTag {\n    fn detach(self, root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        self.listeners.unregister(root);\n\n        let node = self.reference;\n        // recursively remove its children\n        if let BTagInner::Other { child_bundle, .. } = self.inner {\n            // This tag will be removed, so there's no point to remove any child.\n            child_bundle.detach(root, &node, true);\n        }\n        if !parent_to_detach {\n            let result = parent.remove_child(&node);\n\n            if result.is_err() {\n                tracing::warn!(\"Node not found to remove VTag\");\n            }\n        }\n        // It could be that the ref was already reused when rendering another element.\n        // Only unset the ref it still belongs to our node\n        if self.node_ref.get().as_ref() == Some(&node) {\n            self.node_ref.set(None);\n        }\n    }\n\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        slot.insert(next_parent, &self.reference);\n\n        DomSlot::at(self.reference.clone().into())\n    }\n}\n\nimpl Reconcilable for VTag {\n    type Bundle = BTag;\n\n    fn attach(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let el = self.create_element(parent);\n        let Self {\n            listeners,\n            attributes,\n            node_ref,\n            key,\n            ..\n        } = self;\n\n        // Apply attributes BEFORE inserting the element into the DOM\n        // This is crucial for SVG animation elements where the animation\n        // starts immediately upon DOM insertion\n        let attributes = attributes.apply(root, &el);\n        let listeners = listeners.apply(root, &el);\n\n        // Now insert the element with attributes already set\n        slot.insert(parent, &el);\n\n        let inner = match self.inner {\n            VTagInner::Input(f) => {\n                let f = f.apply(root, el.unchecked_ref());\n                BTagInner::Input(f)\n            }\n            VTagInner::Textarea(f) => {\n                let value = f.apply(root, el.unchecked_ref());\n                BTagInner::Textarea { value }\n            }\n            VTagInner::Other { children, tag } => {\n                let (_, child_bundle) = children.attach(root, parent_scope, &el, DomSlot::at_end());\n                BTagInner::Other { child_bundle, tag }\n            }\n        };\n        node_ref.set(Some(el.clone().into()));\n        (\n            DomSlot::at(el.clone().into()),\n            BTag {\n                inner,\n                listeners,\n                reference: el,\n                attributes,\n                key,\n                node_ref,\n            },\n        )\n    }\n\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        // This kind of branching patching routine reduces branch predictor misses and the need to\n        // unpack the enums (including `Option`s) all the time, resulting in a more streamlined\n        // patching flow\n        match bundle {\n            // If the ancestor is a tag of the same type, don't recreate, keep the\n            // old tag and update its attributes and children.\n            BNode::Tag(ex)\n                if self.key == ex.key\n                    && match (&self.inner, &ex.inner) {\n                        (VTagInner::Input(_), BTagInner::Input(_)) => true,\n                        (VTagInner::Textarea { .. }, BTagInner::Textarea { .. }) => true,\n                        (VTagInner::Other { tag: l, .. }, BTagInner::Other { tag: r, .. })\n                            if l == r =>\n                        {\n                            true\n                        }\n                        _ => false,\n                    } =>\n            {\n                return self.reconcile(root, parent_scope, parent, slot, ex.deref_mut());\n            }\n            _ => {}\n        };\n        self.replace(root, parent_scope, parent, slot, bundle)\n    }\n\n    fn reconcile(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        _parent: &Element,\n        _slot: DomSlot,\n        tag: &mut Self::Bundle,\n    ) -> DomSlot {\n        let el = &tag.reference;\n        self.attributes.apply_diff(root, el, &mut tag.attributes);\n        self.listeners.apply_diff(root, el, &mut tag.listeners);\n\n        match (self.inner, &mut tag.inner) {\n            (VTagInner::Input(new), BTagInner::Input(old)) => {\n                new.apply_diff(root, el.unchecked_ref(), old);\n            }\n            (\n                VTagInner::Textarea(TextareaFields { value: new, .. }),\n                BTagInner::Textarea { value: old },\n            ) => {\n                new.apply_diff(root, el.unchecked_ref(), old);\n            }\n            (\n                VTagInner::Other { children: new, .. },\n                BTagInner::Other {\n                    child_bundle: old, ..\n                },\n            ) => {\n                new.reconcile(root, parent_scope, el, DomSlot::at_end(), old);\n            }\n            // Can not happen, because we checked for tag equability above\n            _ => unsafe { unreachable_unchecked() },\n        }\n\n        tag.key = self.key;\n\n        if self.node_ref != tag.node_ref && tag.node_ref.get().as_ref() == Some(el) {\n            tag.node_ref.set(None);\n        }\n        if self.node_ref != tag.node_ref {\n            tag.node_ref = self.node_ref;\n            tag.node_ref.set(Some(el.clone().into()));\n        }\n\n        DomSlot::at(el.clone().into())\n    }\n}\n\nimpl VTag {\n    fn create_element(&self, parent: &Element) -> Element {\n        let tag = self.tag();\n        // check for an xmlns attribute. If it exists, create an element with the specified\n        // namespace\n        if let Some(xmlns) = self\n            .attributes\n            .iter()\n            .find(|(k, _)| *k == \"xmlns\")\n            .map(|(_, v)| v)\n        {\n            document()\n                .create_element_ns(Some(xmlns), tag)\n                .expect(\"can't create namespaced element for vtag\")\n        } else if tag == \"svg\" || parent.namespace_uri().is_some_and(|ns| ns == SVG_NAMESPACE) {\n            let namespace = Some(SVG_NAMESPACE);\n            document()\n                .create_element_ns(namespace, tag)\n                .expect(\"can't create namespaced element for vtag\")\n        } else if tag == \"math\"\n            || parent\n                .namespace_uri()\n                .is_some_and(|ns| ns == MATHML_NAMESPACE)\n        {\n            let namespace = Some(MATHML_NAMESPACE);\n            document()\n                .create_element_ns(namespace, tag)\n                .expect(\"can't create namespaced element for vtag\")\n        } else {\n            thread_local! {\n                static CACHED_ELEMENTS: RefCell<HashMap<String, Element>> = RefCell::new(HashMap::with_capacity(32));\n            }\n\n            CACHED_ELEMENTS.with(|cache| {\n                let mut cache = cache.borrow_mut();\n                let cached = cache.get(tag).map(|el| {\n                    el.clone_node()\n                        .expect(\"couldn't clone cached element\")\n                        .unchecked_into::<Element>()\n                });\n                cached.unwrap_or_else(|| {\n                    let to_be_cached = document()\n                        .create_element(tag)\n                        .expect(\"can't create element for vtag\");\n                    cache.insert(\n                        tag.to_string(),\n                        to_be_cached\n                            .clone_node()\n                            .expect(\"couldn't clone node to be cached\")\n                            .unchecked_into(),\n                    );\n                    to_be_cached\n                })\n            })\n        }\n    }\n}\n\nimpl BTag {\n    /// Get the key of the underlying tag\n    pub fn key(&self) -> Option<&Key> {\n        self.key.as_ref()\n    }\n\n    #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n    #[cfg(test)]\n    fn reference(&self) -> &Element {\n        &self.reference\n    }\n\n    #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n    #[cfg(test)]\n    fn children(&self) -> Option<&BNode> {\n        match &self.inner {\n            BTagInner::Other { child_bundle, .. } => Some(child_bundle),\n            _ => None,\n        }\n    }\n\n    #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n    #[cfg(test)]\n    fn tag(&self) -> &str {\n        match &self.inner {\n            BTagInner::Input { .. } => \"input\",\n            BTagInner::Textarea { .. } => \"textarea\",\n            BTagInner::Other { tag, .. } => tag.as_ref(),\n        }\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use web_sys::Node;\n\n    use super::*;\n    use crate::dom_bundle::{node_type_str, DynamicDomSlot, Fragment, Hydratable};\n\n    impl Hydratable for VTag {\n        fn hydrate(\n            self,\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            _parent: &Element,\n            fragment: &mut Fragment,\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            let tag_name = self.tag().to_owned();\n\n            let Self {\n                inner,\n                listeners,\n                attributes,\n                node_ref,\n                key,\n            } = self;\n\n            // We trim all text nodes as it's likely these are whitespaces.\n            fragment.trim_start_text_nodes();\n\n            let node = fragment\n                .pop_front()\n                .unwrap_or_else(|| panic!(\"expected element of type {tag_name}, found EOF.\"));\n\n            assert_eq!(\n                node.node_type(),\n                Node::ELEMENT_NODE,\n                \"expected element, found node type {}.\",\n                node_type_str(&node),\n            );\n            let el = node.dyn_into::<Element>().expect(\"expected an element.\");\n\n            {\n                let el_tag_name = el.tag_name();\n                let parent_namespace = _parent.namespace_uri();\n\n                // In HTML namespace (or no namespace), createElement is case-insensitive\n                // In other namespaces (SVG, MathML), createElementNS is case-sensitive\n                let should_compare_case_insensitive = parent_namespace.is_none()\n                    || parent_namespace.as_deref() == Some(HTML_NAMESPACE);\n\n                if should_compare_case_insensitive {\n                    // Case-insensitive comparison for HTML elements\n                    assert!(\n                        tag_name.eq_ignore_ascii_case(&el_tag_name),\n                        \"expected element of kind {tag_name}, found {el_tag_name}.\",\n                    );\n                } else {\n                    // Case-sensitive comparison for namespaced elements (SVG, MathML)\n                    assert_eq!(\n                        el_tag_name, tag_name,\n                        \"expected element of kind {tag_name}, found {el_tag_name}.\",\n                    );\n                }\n            }\n            // We simply register listeners and update all attributes.\n            let attributes = attributes.apply(root, &el);\n            let listeners = listeners.apply(root, &el);\n\n            // For input and textarea elements, we update their value anyways.\n            let inner = match inner {\n                VTagInner::Input(f) => {\n                    let f = f.apply(root, el.unchecked_ref());\n                    BTagInner::Input(f)\n                }\n                VTagInner::Textarea(f) => {\n                    let value = f.apply(root, el.unchecked_ref());\n\n                    BTagInner::Textarea { value }\n                }\n                VTagInner::Other { children, tag } => {\n                    let mut nodes = Fragment::collect_children(&el);\n                    let mut prev_next_child = None;\n                    let child_bundle =\n                        children.hydrate(root, parent_scope, &el, &mut nodes, &mut prev_next_child);\n                    if let Some(prev_next_child) = prev_next_child {\n                        prev_next_child.reassign(DomSlot::at_end());\n                    }\n\n                    nodes.trim_start_text_nodes();\n\n                    assert!(nodes.is_empty(), \"expected EOF, found node.\");\n\n                    BTagInner::Other { child_bundle, tag }\n                }\n            };\n\n            node_ref.set(Some((*el).clone()));\n            if let Some(prev_next_sibling) = prev_next_sibling {\n                prev_next_sibling.reassign(DomSlot::at((*el).clone()));\n            }\n            *prev_next_sibling = None;\n\n            BTag {\n                inner,\n                listeners,\n                attributes,\n                reference: el,\n                node_ref,\n                key,\n            }\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod tests {\n    use std::rc::Rc;\n\n    use wasm_bindgen::JsCast;\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n    use web_sys::HtmlInputElement as InputElement;\n\n    use super::*;\n    use crate::dom_bundle::utils::setup_parent;\n    use crate::dom_bundle::{BNode, Reconcilable, ReconcileTarget};\n    use crate::utils::RcExt;\n    use crate::virtual_dom::vtag::{HTML_NAMESPACE, SVG_NAMESPACE};\n    use crate::virtual_dom::{AttrValue, VNode, VTag};\n    use crate::{html, Html, NodeRef};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn it_compares_tags() {\n        let a = html! {\n            <div></div>\n        };\n\n        let b = html! {\n            <div></div>\n        };\n\n        let c = html! {\n            <p></p>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_text() {\n        let a = html! {\n            <div>{ \"correct\" }</div>\n        };\n\n        let b = html! {\n            <div>{ \"correct\" }</div>\n        };\n\n        let c = html! {\n            <div>{ \"incorrect\" }</div>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_attributes_static() {\n        let a = html! {\n            <div a=\"test\"></div>\n        };\n\n        let b = html! {\n            <div a=\"test\"></div>\n        };\n\n        let c = html! {\n            <div a=\"fail\"></div>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_attributes_dynamic() {\n        let a = html! {\n            <div a={\"test\".to_owned()}></div>\n        };\n\n        let b = html! {\n            <div a={\"test\".to_owned()}></div>\n        };\n\n        let c = html! {\n            <div a={\"fail\".to_owned()}></div>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_children() {\n        let a = html! {\n            <div>\n                <p></p>\n            </div>\n        };\n\n        let b = html! {\n            <div>\n                <p></p>\n            </div>\n        };\n\n        let c = html! {\n            <div>\n                <span></span>\n            </div>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_classes_static() {\n        let a = html! {\n            <div class=\"test\"></div>\n        };\n\n        let b = html! {\n            <div class=\"test\"></div>\n        };\n\n        let c = html! {\n            <div class=\"fail\"></div>\n        };\n\n        let d = html! {\n            <div class={format!(\"fail{}\", \"\")}></div>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n        assert_ne!(a, d);\n    }\n\n    #[test]\n    fn it_compares_classes_dynamic() {\n        let a = html! {\n            <div class={\"test\".to_owned()}></div>\n        };\n\n        let b = html! {\n            <div class={\"test\".to_owned()}></div>\n        };\n\n        let c = html! {\n            <div class={\"fail\".to_owned()}></div>\n        };\n\n        let d = html! {\n            <div class={format!(\"fail{}\", \"\")}></div>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n        assert_ne!(a, d);\n    }\n\n    fn assert_vtag(node: VNode) -> VTag {\n        if let VNode::VTag(vtag) = node {\n            return RcExt::unwrap_or_clone(vtag);\n        }\n        panic!(\"should be vtag\");\n    }\n\n    fn assert_btag_ref(node: &BNode) -> &BTag {\n        if let BNode::Tag(vtag) = node {\n            return vtag;\n        }\n        panic!(\"should be btag\");\n    }\n\n    fn assert_vtag_ref(node: &VNode) -> &VTag {\n        if let VNode::VTag(vtag) = node {\n            return vtag;\n        }\n        panic!(\"should be vtag\");\n    }\n\n    fn assert_btag_mut(node: &mut BNode) -> &mut BTag {\n        if let BNode::Tag(btag) = node {\n            return btag;\n        }\n        panic!(\"should be btag\");\n    }\n\n    fn assert_namespace(vtag: &BTag, namespace: &'static str) {\n        assert_eq!(vtag.reference().namespace_uri().unwrap(), namespace);\n    }\n\n    #[test]\n    fn supports_svg() {\n        let (root, scope, parent) = setup_parent();\n        let document = web_sys::window().unwrap().document().unwrap();\n\n        let namespace = SVG_NAMESPACE;\n        let namespace = Some(namespace);\n        let svg_el = document.create_element_ns(namespace, \"svg\").unwrap();\n\n        let g_node = html! { <g class=\"segment\"></g> };\n        let path_node = html! { <path></path> };\n        let svg_node = html! { <svg>{path_node}</svg> };\n\n        let svg_tag = assert_vtag(svg_node);\n        let (_, svg_tag) = svg_tag.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_namespace(&svg_tag, SVG_NAMESPACE);\n        let path_tag = assert_btag_ref(svg_tag.children().unwrap());\n        assert_namespace(path_tag, SVG_NAMESPACE);\n\n        let g_tag = assert_vtag(g_node.clone());\n        let (_, g_tag) = g_tag.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_namespace(&g_tag, HTML_NAMESPACE);\n\n        let g_tag = assert_vtag(g_node);\n        let (_, g_tag) = g_tag.attach(&root, &scope, &svg_el, DomSlot::at_end());\n        assert_namespace(&g_tag, SVG_NAMESPACE);\n    }\n\n    #[test]\n    fn supports_mathml() {\n        let (root, scope, parent) = setup_parent();\n        let mfrac_node = html! { <mfrac> </mfrac> };\n        let math_node = html! { <math>{mfrac_node}</math> };\n\n        let math_tag = assert_vtag(math_node);\n        let (_, math_tag) = math_tag.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_namespace(&math_tag, MATHML_NAMESPACE);\n        let mfrac_tag = assert_btag_ref(math_tag.children().unwrap());\n        assert_namespace(mfrac_tag, MATHML_NAMESPACE);\n    }\n\n    #[test]\n    fn it_compares_values() {\n        let a = html! {\n            <input value=\"test\"/>\n        };\n\n        let b = html! {\n            <input value=\"test\"/>\n        };\n\n        let c = html! {\n            <input value=\"fail\"/>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_kinds() {\n        let a = html! {\n            <input type=\"text\"/>\n        };\n\n        let b = html! {\n            <input type=\"text\"/>\n        };\n\n        let c = html! {\n            <input type=\"hidden\"/>\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_compares_checked() {\n        let a = html! {\n            <input type=\"checkbox\" checked=false />\n        };\n\n        let b = html! {\n            <input type=\"checkbox\" checked=false />\n        };\n\n        let c = html! {\n            <input type=\"checkbox\" checked=true />\n        };\n\n        assert_eq!(a, b);\n        assert_ne!(a, c);\n    }\n\n    #[test]\n    fn it_allows_aria_attributes() {\n        let a = html! {\n            <p aria-controls=\"it-works\">\n                <a class=\"btn btn-primary\"\n                   data-toggle=\"collapse\"\n                   href=\"#collapseExample\"\n                   role=\"button\"\n                   aria-expanded=\"false\"\n                   aria-controls=\"collapseExample\">\n                    { \"Link with href\" }\n                </a>\n                <button class=\"btn btn-primary\"\n                        type=\"button\"\n                        data-toggle=\"collapse\"\n                        data-target=\"#collapseExample\"\n                        aria-expanded=\"false\"\n                        aria-controls=\"collapseExample\">\n                    { \"Button with data-target\" }\n                </button>\n                <div own-attribute-with-multiple-parts=\"works\" />\n            </p>\n        };\n        if let VNode::VTag(vtag) = a {\n            assert_eq!(\n                vtag.attributes\n                    .iter()\n                    .find(|(k, _)| k == &\"aria-controls\")\n                    .map(|(_, v)| v),\n                Some(\"it-works\")\n            );\n        } else {\n            panic!(\"vtag expected\");\n        }\n    }\n\n    #[test]\n    fn it_does_not_set_missing_class_name() {\n        let (root, scope, parent) = setup_parent();\n\n        let elem = html! { <div></div> };\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        let vtag = assert_btag_mut(&mut elem);\n        // test if the className has not been set\n        assert!(!vtag.reference().has_attribute(\"class\"));\n    }\n\n    fn test_set_class_name(gen_html: impl FnOnce() -> Html) {\n        let (root, scope, parent) = setup_parent();\n\n        let elem = gen_html();\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        let vtag = assert_btag_mut(&mut elem);\n        // test if the className has been set\n        assert!(vtag.reference().has_attribute(\"class\"));\n    }\n\n    #[test]\n    fn it_sets_class_name_static() {\n        test_set_class_name(|| html! { <div class=\"ferris the crab\"></div> });\n    }\n\n    #[test]\n    fn it_sets_class_name_dynamic() {\n        test_set_class_name(|| html! { <div class={\"ferris the crab\".to_owned()}></div> });\n    }\n\n    #[test]\n    fn controlled_input_synced() {\n        let (root, scope, parent) = setup_parent();\n\n        let expected = \"not_changed_value\";\n\n        // Initial state\n        let elem = html! { <input value={expected} /> };\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        let vtag = assert_btag_ref(&elem);\n\n        // User input\n        let input_ref = &vtag.reference();\n        let input = input_ref.dyn_ref::<InputElement>();\n        input.unwrap().set_value(\"User input\");\n\n        let next_elem = html! { <input value={expected} /> };\n        let elem_vtag = assert_vtag(next_elem);\n\n        // Sync happens here\n        elem_vtag.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut elem);\n        let vtag = assert_btag_ref(&elem);\n\n        // Get new current value of the input element\n        let input_ref = &vtag.reference();\n        let input = input_ref.dyn_ref::<InputElement>().unwrap();\n\n        let current_value = input.value();\n\n        // check whether not changed virtual dom value has been set to the input element\n        assert_eq!(current_value, expected);\n    }\n\n    #[test]\n    fn uncontrolled_input_unsynced() {\n        let (root, scope, parent) = setup_parent();\n\n        // Initial state\n        let elem = html! { <input /> };\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        let vtag = assert_btag_ref(&elem);\n\n        // User input\n        let input_ref = &vtag.reference();\n        let input = input_ref.dyn_ref::<InputElement>();\n        input.unwrap().set_value(\"User input\");\n\n        let next_elem = html! { <input /> };\n        let elem_vtag = assert_vtag(next_elem);\n\n        // Value should not be refreshed\n        elem_vtag.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut elem);\n        let vtag = assert_btag_ref(&elem);\n\n        // Get user value of the input element\n        let input_ref = &vtag.reference();\n        let input = input_ref.dyn_ref::<InputElement>().unwrap();\n\n        let current_value = input.value();\n\n        // check whether not changed virtual dom value has been set to the input element\n        assert_eq!(current_value, \"User input\");\n\n        // Need to remove the element to clean up the dirty state of the DOM. Failing this causes\n        // event listener tests to fail.\n        parent.remove();\n    }\n\n    #[test]\n    fn dynamic_tags_work() {\n        let (root, scope, parent) = setup_parent();\n\n        let elem = html! { <@{{\n            let mut builder = String::new();\n            builder.push('a');\n            builder\n        }}/> };\n\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        let vtag = assert_btag_mut(&mut elem);\n        // make sure the new tag name is used internally\n        assert_eq!(vtag.tag(), \"a\");\n\n        // Element.tagName is always in the canonical upper-case form.\n        assert_eq!(vtag.reference().tag_name(), \"A\");\n    }\n\n    #[test]\n    fn dynamic_tags_handle_value_attribute() {\n        let div_el = html! {\n            <@{\"div\"} value=\"Hello\"/>\n        };\n        let div_vtag = assert_vtag_ref(&div_el);\n        assert!(div_vtag.value().is_none());\n        let v: Option<&str> = div_vtag\n            .attributes\n            .iter()\n            .find(|(k, _)| k == &\"value\")\n            .map(|(_, v)| AsRef::as_ref(v));\n        assert_eq!(v, Some(\"Hello\"));\n\n        let input_el = html! {\n            <@{\"input\"} value=\"World\"/>\n        };\n        let input_vtag = assert_vtag_ref(&input_el);\n        assert_eq!(input_vtag.value(), Some(&AttrValue::Static(\"World\")));\n        assert!(!input_vtag.attributes.iter().any(|(k, _)| k == \"value\"));\n    }\n\n    #[test]\n    fn dynamic_tags_handle_weird_capitalization() {\n        let el = html! {\n            <@{\"tExTAREa\"}/>\n        };\n        let vtag = assert_vtag_ref(&el);\n        // textarea is a special element, so it gets normalized\n        assert_eq!(vtag.tag(), \"textarea\");\n    }\n\n    #[test]\n    fn dynamic_tags_allow_custom_capitalization() {\n        let el = html! {\n            <@{\"clipPath\"}/>\n        };\n        let vtag = assert_vtag_ref(&el);\n        // no special treatment for elements not recognized e.g. clipPath\n        assert_eq!(vtag.tag(), \"clipPath\");\n    }\n\n    #[test]\n    fn reset_node_ref() {\n        let (root, scope, parent) = setup_parent();\n\n        let node_ref = NodeRef::default();\n        let elem: VNode = html! { <div ref={node_ref.clone()}></div> };\n        assert_vtag_ref(&elem);\n        let (_, elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n        assert_eq!(node_ref.get(), parent.first_child());\n        elem.detach(&root, &parent, false);\n        assert!(node_ref.get().is_none());\n    }\n\n    #[test]\n    fn vtag_reuse_should_reset_ancestors_node_ref() {\n        let (root, scope, parent) = setup_parent();\n\n        let node_ref_a = NodeRef::default();\n        let elem_a = html! { <div id=\"a\" ref={node_ref_a.clone()} /> };\n        let (_, mut elem) = elem_a.attach(&root, &scope, &parent, DomSlot::at_end());\n\n        // save the Node to check later that it has been reused.\n        let node_a = node_ref_a.get().unwrap();\n\n        let node_ref_b = NodeRef::default();\n        let elem_b = html! { <div id=\"b\" ref={node_ref_b.clone()} /> };\n        elem_b.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut elem);\n\n        let node_b = node_ref_b.get().unwrap();\n\n        assert_eq!(node_a, node_b, \"VTag should have reused the element\");\n        assert!(\n            node_ref_a.get().is_none(),\n            \"node_ref_a should have been reset when the element was reused.\"\n        );\n    }\n\n    #[test]\n    fn vtag_should_not_touch_newly_bound_refs() {\n        let (root, scope, parent) = setup_parent();\n\n        let test_ref = NodeRef::default();\n        let before = html! {\n            <>\n                <div ref={&test_ref} id=\"before\" />\n            </>\n        };\n        let after = html! {\n            <>\n                <h6 />\n                <div ref={&test_ref} id=\"after\" />\n            </>\n        };\n        // The point of this diff is to first render the \"after\" div and then detach the \"before\"\n        // div, while both should be bound to the same node ref\n\n        let (_, mut elem) = before.attach(&root, &scope, &parent, DomSlot::at_end());\n        after.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut elem);\n\n        assert_eq!(\n            test_ref\n                .get()\n                .unwrap()\n                .dyn_ref::<web_sys::Element>()\n                .unwrap()\n                .outer_html(),\n            \"<div id=\\\"after\\\"></div>\"\n        );\n    }\n\n    // test for bug: https://github.com/yewstack/yew/pull/2653\n    #[test]\n    fn test_index_map_attribute_diff() {\n        let (root, scope, parent) = setup_parent();\n\n        let test_ref = NodeRef::default();\n\n        // We want to test apply_diff with Attributes::IndexMap, so we\n        // need to create the VTag manually\n\n        // Create <div disabled=\"disabled\" tabindex=\"0\">\n        let mut vtag = VTag::new(\"div\");\n        vtag.node_ref = test_ref.clone();\n        vtag.add_attribute(\"disabled\", \"disabled\");\n        vtag.add_attribute(\"tabindex\", \"0\");\n\n        let elem = VNode::VTag(Rc::new(vtag));\n\n        let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end());\n\n        // Create <div tabindex=\"0\"> (removed first attribute \"disabled\")\n        let mut vtag = VTag::new(\"div\");\n        vtag.node_ref = test_ref.clone();\n        vtag.add_attribute(\"tabindex\", \"0\");\n        let next_elem = VNode::VTag(Rc::new(vtag));\n        let elem_vtag = assert_vtag(next_elem);\n\n        // Sync happens here\n        // this should remove the \"disabled\" attribute\n        elem_vtag.reconcile_node(&root, &scope, &parent, DomSlot::at_end(), &mut elem);\n\n        assert_eq!(\n            test_ref\n                .get()\n                .unwrap()\n                .dyn_ref::<web_sys::Element>()\n                .unwrap()\n                .outer_html(),\n            \"<div tabindex=\\\"0\\\"></div>\"\n        );\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    extern crate self as yew;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use crate::html;\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn diff() {\n        let layout1 = TestLayout {\n            name: \"1\",\n            node: html! {\n                <ul>\n                    <li>\n                        {\"a\"}\n                    </li>\n                    <li>\n                        {\"b\"}\n                    </li>\n                </ul>\n            },\n            expected: \"<ul><li>a</li><li>b</li></ul>\",\n        };\n\n        let layout2 = TestLayout {\n            name: \"2\",\n            node: html! {\n                <ul>\n                    <li>\n                        {\"a\"}\n                    </li>\n                    <li>\n                        {\"b\"}\n                    </li>\n                    <li>\n                        {\"d\"}\n                    </li>\n                </ul>\n            },\n            expected: \"<ul><li>a</li><li>b</li><li>d</li></ul>\",\n        };\n\n        let layout3 = TestLayout {\n            name: \"3\",\n            node: html! {\n                <ul>\n                    <li>\n                        {\"a\"}\n                    </li>\n                    <li>\n                        {\"b\"}\n                    </li>\n                    <li>\n                        {\"c\"}\n                    </li>\n                    <li>\n                        {\"d\"}\n                    </li>\n                </ul>\n            },\n            expected: \"<ul><li>a</li><li>b</li><li>c</li><li>d</li></ul>\",\n        };\n\n        let layout4 = TestLayout {\n            name: \"4\",\n            node: html! {\n                <ul>\n                    <li>\n                        <>\n                            {\"a\"}\n                        </>\n                    </li>\n                    <li>\n                        {\"b\"}\n                        <li>\n                            {\"c\"}\n                        </li>\n                        <li>\n                            {\"d\"}\n                        </li>\n                    </li>\n                </ul>\n            },\n            expected: \"<ul><li>a</li><li>b<li>c</li><li>d</li></li></ul>\",\n        };\n\n        diff_layouts(vec![layout1, layout2, layout3, layout4]);\n    }\n}\n\n#[cfg(test)]\nmod tests_without_browser {\n    use crate::html;\n    use crate::virtual_dom::VNode;\n\n    #[test]\n    fn html_if_bool() {\n        assert_eq!(\n            html! {\n                if true {\n                    <div class=\"foo\" />\n                }\n            },\n            html! {\n                <>\n                    <div class=\"foo\" />\n                </>\n            },\n        );\n        assert_eq!(\n            html! {\n                if false {\n                    <div class=\"foo\" />\n                } else {\n                    <div class=\"bar\" />\n                }\n            },\n            html! {\n                <><div class=\"bar\" /></>\n            },\n        );\n        assert_eq!(\n            html! {\n                if false {\n                    <div class=\"foo\" />\n                }\n            },\n            html! {\n                <></>\n            },\n        );\n\n        // non-root tests\n        assert_eq!(\n            html! {\n                <div>\n                    if true {\n                        <div class=\"foo\" />\n                    }\n                </div>\n            },\n            html! {\n                <div>\n                    <><div class=\"foo\" /></>\n                </div>\n            },\n        );\n        assert_eq!(\n            html! {\n                <div>\n                    if false {\n                        <div class=\"foo\" />\n                    } else {\n                        <div class=\"bar\" />\n                    }\n                </div>\n            },\n            html! {\n                <div>\n                    <><div class=\"bar\" /></>\n                </div>\n            },\n        );\n        assert_eq!(\n            html! {\n                <div>\n                    if false {\n                        <div class=\"foo\" />\n                    }\n                </div>\n            },\n            html! {\n                <div>\n                    <></>\n                </div>\n            },\n        );\n    }\n\n    #[test]\n    fn html_if_option() {\n        let option_foo = Some(\"foo\");\n        let none: Option<&'static str> = None;\n        assert_eq!(\n            html! {\n                if let Some(class) = option_foo {\n                    <div class={class} />\n                }\n            },\n            html! {\n                <>\n                    <div class={Some(\"foo\")} />\n                </>\n            },\n        );\n        assert_eq!(\n            html! {\n                if let Some(class) = none {\n                    <div class={class} />\n                } else {\n                    <div class=\"bar\" />\n                }\n            },\n            html! {\n                <>\n                    <div class=\"bar\" />\n                </>\n            },\n        );\n        assert_eq!(\n            html! {\n                if let Some(class) = none {\n                    <div class={class} />\n                }\n            },\n            html! {\n                <></>\n            },\n        );\n\n        // non-root tests\n        assert_eq!(\n            html! {\n                <div>\n                    if let Some(class) = option_foo {\n                        <div class={class} />\n                    }\n                </div>\n            },\n            html! {\n                <div>\n                    <>\n                        <div class={Some(\"foo\")} />\n                    </>\n                </div>\n            },\n        );\n        assert_eq!(\n            html! {\n                <div>\n                    if let Some(class) = none {\n                        <div class={class} />\n                    } else {\n                        <div class=\"bar\" />\n                    }\n                </div>\n            },\n            html! {\n                <div>\n                    <>\n                        <div class=\"bar\" />\n                    </>\n                </div>\n            },\n        );\n        assert_eq!(\n            html! {\n                <div>\n                    if let Some(class) = none {\n                        <div class={class} />\n                    }\n                </div>\n            },\n            html! { <div><></></div> },\n        );\n    }\n\n    #[test]\n    fn input_checked_stays_there() {\n        let tag = html! {\n            <input checked={true} />\n        };\n        match tag {\n            VNode::VTag(tag) => {\n                assert_eq!(tag.checked(), Some(true));\n            }\n            _ => unreachable!(),\n        }\n    }\n    #[test]\n    fn non_input_checked_stays_there() {\n        let tag = html! {\n            <my-el checked=\"true\" />\n        };\n        match tag {\n            VNode::VTag(tag) => {\n                assert_eq!(\n                    tag.attributes.iter().find(|(k, _)| *k == \"checked\"),\n                    Some((\"checked\", \"true\"))\n                );\n            }\n            _ => unreachable!(),\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/btext.rs",
    "content": "//! This module contains the bundle implementation of text [BText].\n\nuse gloo::utils::document;\nuse web_sys::{Element, Text as TextNode};\n\nuse super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget};\nuse crate::html::AnyScope;\nuse crate::virtual_dom::{AttrValue, VText};\n\n/// The bundle implementation to [VText]\npub(super) struct BText {\n    text: AttrValue,\n    text_node: TextNode,\n}\n\nimpl ReconcileTarget for BText {\n    fn detach(self, _root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        if !parent_to_detach {\n            let result = parent.remove_child(&self.text_node);\n\n            if result.is_err() {\n                tracing::warn!(\"Node not found to remove VText\");\n            }\n        }\n    }\n\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        slot.insert(next_parent, &self.text_node);\n\n        DomSlot::at(self.text_node.clone().into())\n    }\n}\n\nimpl Reconcilable for VText {\n    type Bundle = BText;\n\n    fn attach(\n        self,\n        _root: &BSubtree,\n        _parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle) {\n        let Self { text } = self;\n        let text_node = document().create_text_node(&text);\n        slot.insert(parent, &text_node);\n        let node_ref = DomSlot::at(text_node.clone().into());\n        (node_ref, BText { text, text_node })\n    }\n\n    /// Renders virtual node over existing `TextNode`, but only if value of text has changed.\n    fn reconcile_node(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot {\n        match bundle {\n            BNode::Text(btext) => self.reconcile(root, parent_scope, parent, slot, btext),\n            _ => self.replace(root, parent_scope, parent, slot, bundle),\n        }\n    }\n\n    fn reconcile(\n        self,\n        _root: &BSubtree,\n        _parent_scope: &AnyScope,\n        _parent: &Element,\n        _slot: DomSlot,\n        btext: &mut Self::Bundle,\n    ) -> DomSlot {\n        let Self { text } = self;\n        let ancestor_text = std::mem::replace(&mut btext.text, text);\n        if btext.text != ancestor_text {\n            btext.text_node.set_node_value(Some(&btext.text));\n        }\n        DomSlot::at(btext.text_node.clone().into())\n    }\n}\n\nimpl std::fmt::Debug for BText {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"BText\").field(\"text\", &self.text).finish()\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use wasm_bindgen::JsCast;\n    use web_sys::Node;\n\n    use super::*;\n    use crate::dom_bundle::{DynamicDomSlot, Fragment, Hydratable};\n\n    impl Hydratable for VText {\n        fn hydrate(\n            self,\n            _root: &BSubtree,\n            _parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            previous_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle {\n            let create_at = |next_sibling: Option<Node>, text: AttrValue| {\n                // If there are multiple text nodes placed back-to-back in SSR, it may be parsed as\n                // a single text node by browser, hence we need to add extra text\n                // nodes here if the next node is not a text node. Similarly, the\n                // value of the text node may be a combination of multiple VText\n                // vnodes. So we always need to override their values.\n                let text_node = document().create_text_node(text.as_ref());\n                DomSlot::create(next_sibling).insert(parent, &text_node);\n                BText { text, text_node }\n            };\n            let btext = if let Some(m) = fragment.front().cloned() {\n                if m.node_type() == Node::TEXT_NODE {\n                    let m = m.unchecked_into::<TextNode>();\n                    // pop current node.\n                    fragment.pop_front();\n\n                    // TODO: It may make sense to assert the text content in the text node\n                    // against the VText when #[cfg(debug_assertions)]\n                    // is true, but this may be complicated.\n                    // We always replace the text value for now.\n                    //\n                    // Please see the next comment for a detailed explanation.\n                    m.set_node_value(Some(self.text.as_ref()));\n\n                    BText {\n                        text: self.text,\n                        text_node: m,\n                    }\n                } else {\n                    create_at(Some(m), self.text)\n                }\n            } else {\n                create_at(fragment.sibling_at_end().cloned(), self.text)\n            };\n            if let Some(previous_next_sibling) = previous_next_sibling {\n                previous_next_sibling.reassign(DomSlot::at(btext.text_node.clone().into()));\n            }\n            *previous_next_sibling = None;\n            btext\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    extern crate self as yew;\n\n    #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use crate::html;\n\n    #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn text_as_root() {\n        let _ = html! {\n            \"Text Node As Root\"\n        };\n\n        let _ = html! {\n            { \"Text Node As Root\" }\n        };\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    extern crate self as yew;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use crate::html;\n    use crate::tests::layout_tests::{diff_layouts, TestLayout};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn diff() {\n        let layout1 = TestLayout {\n            name: \"1\",\n            node: html! { \"a\" },\n            expected: \"a\",\n        };\n\n        let layout2 = TestLayout {\n            name: \"2\",\n            node: html! { \"b\" },\n            expected: \"b\",\n        };\n\n        let layout3 = TestLayout {\n            name: \"3\",\n            node: html! {\n                <>\n                    {\"a\"}\n                    {\"b\"}\n                </>\n            },\n            expected: \"ab\",\n        };\n\n        let layout4 = TestLayout {\n            name: \"4\",\n            node: html! {\n                <>\n                    {\"b\"}\n                    {\"a\"}\n                </>\n            },\n            expected: \"ba\",\n        };\n\n        diff_layouts(vec![layout1, layout2, layout3, layout4]);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/fragment.rs",
    "content": "use std::collections::VecDeque;\nuse std::ops::{Deref, DerefMut};\n\nuse wasm_bindgen::JsCast;\nuse web_sys::{Element, Node};\n\nuse super::{BSubtree, DomSlot};\nuse crate::virtual_dom::Collectable;\n\n/// A Hydration Fragment\n#[derive(Default, Debug, Clone, PartialEq, Eq)]\npub(crate) struct Fragment(VecDeque<Node>, Option<Node>);\n\nimpl Deref for Fragment {\n    type Target = VecDeque<Node>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl DerefMut for Fragment {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\nimpl Fragment {\n    /// Collects child nodes of an element into a VecDeque.\n    pub fn collect_children(parent: &Element) -> Self {\n        let mut fragment = VecDeque::with_capacity(parent.child_nodes().length() as usize);\n\n        let mut current_node = parent.first_child();\n\n        // This is easier than iterating child nodes at the moment\n        // as we don't have to downcast iterator values.\n        while let Some(m) = current_node {\n            current_node = m.next_sibling();\n            fragment.push_back(m);\n        }\n\n        Self(fragment, None)\n    }\n\n    /// Collects nodes for a Component Bundle or a BSuspense.\n    pub fn collect_between(\n        collect_from: &mut Fragment,\n        collect_for: &Collectable,\n        parent: &Element,\n    ) -> Self {\n        let is_open_tag = |node: &Node| {\n            let comment_text = node.text_content().unwrap_or_default();\n\n            comment_text.starts_with(collect_for.open_start_mark())\n                && comment_text.ends_with(collect_for.end_mark())\n        };\n\n        let is_close_tag = |node: &Node| {\n            let comment_text = node.text_content().unwrap_or_default();\n\n            comment_text.starts_with(collect_for.close_start_mark())\n                && comment_text.ends_with(collect_for.end_mark())\n        };\n\n        // We trim all leading text nodes as it's likely these are whitespaces.\n        collect_from.trim_start_text_nodes();\n\n        let first_node = collect_from\n            .pop_front()\n            .unwrap_or_else(|| panic!(\"expected {} opening tag, found EOF\", collect_for.name()));\n\n        assert_eq!(\n            first_node.node_type(),\n            Node::COMMENT_NODE,\n            // TODO: improve error message with human readable node type name.\n            \"expected {} start, found node type {}\",\n            collect_for.name(),\n            first_node.node_type()\n        );\n\n        let mut nodes = VecDeque::new();\n\n        if !is_open_tag(&first_node) {\n            panic!(\n                \"expected {} opening tag, found comment node\",\n                collect_for.name()\n            );\n        }\n\n        // We remove the opening tag.\n        parent.remove_child(&first_node).unwrap();\n\n        let mut nested_layers = 1;\n\n        loop {\n            let current_node = collect_from.pop_front().unwrap_or_else(|| {\n                panic!(\"expected {} closing tag, found EOF\", collect_for.name())\n            });\n\n            if current_node.node_type() == Node::COMMENT_NODE {\n                if is_open_tag(&current_node) {\n                    // We found another opening tag, we need to increase component counter.\n                    nested_layers += 1;\n                } else if is_close_tag(&current_node) {\n                    // We found a closing tag, minus component counter.\n                    nested_layers -= 1;\n                    if nested_layers == 0 {\n                        // We have found the end of the current tag we are collecting, breaking\n                        // the loop.\n\n                        // We remove the closing tag.\n                        parent.remove_child(&current_node).unwrap();\n                        break;\n                    }\n                }\n            }\n\n            nodes.push_back(current_node);\n        }\n\n        let next_child = collect_from.0.front().cloned();\n        Self(nodes, next_child)\n    }\n\n    /// Remove child nodes until first non-text node.\n    pub fn trim_start_text_nodes(&mut self) {\n        while let Some(ref m) = self.front().cloned() {\n            if m.node_type() == Node::TEXT_NODE {\n                self.pop_front();\n\n                m.unchecked_ref::<web_sys::Text>().remove();\n            } else {\n                break;\n            }\n        }\n    }\n\n    /// Deeply clones all nodes.\n    pub fn deep_clone(&self) -> Self {\n        let nodes = self\n            .iter()\n            .map(|m| m.clone_node_with_deep(true).expect(\"failed to clone node.\"))\n            .collect::<VecDeque<_>>();\n\n        // the cloned nodes are disconnected from the real dom, so next_child is `None`\n        Self(nodes, None)\n    }\n\n    // detaches current fragment.\n    pub fn detach(self, _root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        if !parent_to_detach {\n            for node in self.iter() {\n                parent\n                    .remove_child(node)\n                    .expect(\"failed to remove child element\");\n            }\n        }\n    }\n\n    /// Shift current Fragment into a different position in the dom.\n    pub fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {\n        for node in self.iter() {\n            slot.insert(next_parent, node);\n        }\n\n        self.front().cloned().map(DomSlot::at).unwrap_or(slot)\n    }\n\n    /// Return the node that comes after all the nodes in this fragment\n    pub fn sibling_at_end(&self) -> Option<&Node> {\n        self.1.as_ref()\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/mod.rs",
    "content": "//! Realizing a virtual dom on the actual DOM\n//!\n//! A bundle, borrowed from the mathematical meaning, is any structure over some base space.\n//! In our case, the base space is the virtual dom we're trying to render.\n//! In order to efficiently implement updates, and diffing, additional information has to be\n//! kept around. This information is carried in the bundle.\n\nuse web_sys::Element;\n\nuse crate::html::AnyScope;\nuse crate::virtual_dom::VNode;\n\nmod bcomp;\nmod blist;\nmod bnode;\nmod bportal;\nmod braw;\nmod bsuspense;\nmod btag;\nmod btext;\nmod position;\nmod subtree_root;\n\nmod traits;\nmod utils;\n\nuse bcomp::BComp;\nuse blist::BList;\nuse bnode::BNode;\nuse bportal::BPortal;\nuse braw::BRaw;\nuse bsuspense::BSuspense;\nuse btag::{BTag, Registry};\nuse btext::BText;\npub(crate) use position::{DomSlot, DynamicDomSlot};\nuse subtree_root::EventDescriptor;\npub use subtree_root::{set_event_bubbling, BSubtree};\nuse traits::{Reconcilable, ReconcileTarget};\nuse utils::test_log;\n\n/// A Bundle.\n///\n/// Each component holds a bundle that represents a realised layout, designated by a [VNode].\n///\n/// This is not to be confused with [BComp], which represents a component in the position of a\n/// bundle layout.\n#[derive(Debug)]\npub(crate) struct Bundle(BNode);\n\nimpl Bundle {\n    /// Creates a new bundle.\n    pub const fn new() -> Self {\n        Self(BNode::List(BList::new()))\n    }\n\n    /// Shifts the bundle into a different position.\n    pub fn shift(&self, next_parent: &Element, slot: DomSlot) {\n        self.0.shift(next_parent, slot);\n    }\n\n    /// Applies a virtual dom layout to current bundle.\n    pub fn reconcile(\n        &mut self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        next_node: VNode,\n    ) -> DomSlot {\n        next_node.reconcile_node(root, parent_scope, parent, slot, &mut self.0)\n    }\n\n    /// Detaches current bundle.\n    pub fn detach(self, root: &BSubtree, parent: &Element, parent_to_detach: bool) {\n        self.0.detach(root, parent, parent_to_detach);\n    }\n}\n\n#[cfg(feature = \"hydration\")]\n#[path = \".\"]\nmod feat_hydration {\n    pub(super) use super::traits::Hydratable;\n    pub(super) use super::utils::node_type_str;\n    #[path = \"./fragment.rs\"]\n    mod fragment;\n    pub(crate) use fragment::Fragment;\n\n    use super::*;\n    impl Bundle {\n        /// Creates a bundle by hydrating a virtual dom layout.\n        pub fn hydrate(\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            node: VNode,\n            previous_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self {\n            let bundle = node.hydrate(root, parent_scope, parent, fragment, previous_next_sibling);\n            Self(bundle)\n        }\n    }\n}\n#[cfg(feature = \"hydration\")]\npub(crate) use feat_hydration::*;\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/position.rs",
    "content": "//! Structs for keeping track where in the DOM a node belongs\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse web_sys::{Element, Node};\n\n/// A position in the list of children of an implicit parent [`Element`].\n///\n/// This can either be in front of a `DomSlot::at(next_sibling)`, at the end of the list with\n/// `DomSlot::at_end()`, or a dynamic position in the list with [`DynamicDomSlot::to_position`].\n#[derive(Clone)]\npub(crate) struct DomSlot {\n    variant: DomSlotVariant,\n}\n\n#[derive(Clone)]\nenum DomSlotVariant {\n    Node(Option<Node>),\n    Chained(DynamicDomSlot),\n}\n\n/// A dynamic dom slot can be reassigned. This change is also seen by the [`DomSlot`] from\n/// [`Self::to_position`] before the reassignment took place.\n#[derive(Clone)]\npub(crate) struct DynamicDomSlot {\n    target: Rc<RefCell<DomSlot>>,\n}\n\nimpl std::fmt::Debug for DomSlot {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        self.with_next_sibling(|n| {\n            let formatted_node = match n {\n                None => None,\n                Some(n) if trap_impl::is_trap(n) => Some(\"<not yet initialized />\".to_string()),\n                Some(n) => Some(crate::utils::print_node(n)),\n            };\n            write!(f, \"DomSlot {{ next_sibling: {formatted_node:?} }}\")\n        })\n    }\n}\n\nimpl std::fmt::Debug for DynamicDomSlot {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{:#?}\", *self.target.borrow())\n    }\n}\n\nmod trap_impl {\n    use super::Node;\n    #[cfg(debug_assertions)]\n    thread_local! {\n        // A special marker element that should not be referenced\n        static TRAP: Node = gloo::utils::document().create_element(\"div\").unwrap().into();\n    }\n    /// Get a \"trap\" node, or None if compiled without debug_assertions\n    #[cfg(feature = \"hydration\")]\n    pub fn get_trap_node() -> Option<Node> {\n        #[cfg(debug_assertions)]\n        {\n            TRAP.with(|trap| Some(trap.clone()))\n        }\n        #[cfg(not(debug_assertions))]\n        {\n            None\n        }\n    }\n    #[inline]\n    pub fn is_trap(node: &Node) -> bool {\n        #[cfg(debug_assertions)]\n        {\n            TRAP.with(|trap| node == trap)\n        }\n        #[cfg(not(debug_assertions))]\n        {\n            // When not running with debug_assertions, there is no trap node\n            let _ = node;\n            false\n        }\n    }\n}\n\nimpl DomSlot {\n    /// Denotes the position just before the given node in its parent's list of children.\n    pub fn at(next_sibling: Node) -> Self {\n        Self::create(Some(next_sibling))\n    }\n\n    /// Denotes the position at the end of a list of children. The parent is implicit.\n    pub fn at_end() -> Self {\n        Self::create(None)\n    }\n\n    pub fn create(next_sibling: Option<Node>) -> Self {\n        Self {\n            variant: DomSlotVariant::Node(next_sibling),\n        }\n    }\n\n    /// A new \"placeholder\" [DomSlot] that should not be used to insert nodes\n    #[inline]\n    #[cfg(feature = \"hydration\")]\n    pub fn new_debug_trapped() -> Self {\n        Self::create(trap_impl::get_trap_node())\n    }\n\n    /// Get the [Node] that comes just after the position, or `None` if this denotes the position at\n    /// the end\n    fn with_next_sibling_check_trap<R>(&self, f: impl FnOnce(Option<&Node>) -> R) -> R {\n        let checkedf = |node: Option<&Node>| {\n            // MSRV 1.82 could rewrite this with `is_none_or`\n            let is_trapped = match node {\n                None => false,\n                Some(node) => trap_impl::is_trap(node),\n            };\n            assert!(\n                !is_trapped,\n                \"Should not use a trapped DomSlot. Please report this as an internal bug in yew.\"\n            );\n            f(node)\n        };\n        self.with_next_sibling(checkedf)\n    }\n\n    fn with_next_sibling<R>(&self, f: impl FnOnce(Option<&Node>) -> R) -> R {\n        match &self.variant {\n            DomSlotVariant::Node(ref n) => f(n.as_ref()),\n            DomSlotVariant::Chained(ref chain) => chain.with_next_sibling(f),\n        }\n    }\n\n    /// Insert a [Node] at the position denoted by this slot. `parent` must be the actual parent\n    /// element of the children that this slot is implicitly a part of.\n    pub(super) fn insert(&self, parent: &Element, node: &Node) {\n        self.with_next_sibling_check_trap(|next_sibling: Option<&Node>| {\n            parent\n                .insert_before(node, next_sibling)\n                .unwrap_or_else(|err| {\n                    let msg = if next_sibling.is_some() {\n                        \"failed to insert node before next sibling\"\n                    } else {\n                        \"failed to append child\"\n                    };\n                    // Log normally, so we can inspect the nodes in console\n                    gloo::console::error!(msg, err, parent, next_sibling, node);\n                    // Log via tracing for consistency\n                    tracing::error!(msg);\n                    // Panic to short-circuit and fail\n                    panic!(\"{}\", msg)\n                });\n        });\n    }\n\n    #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n    #[cfg(test)]\n    fn get(&self) -> Option<Node> {\n        self.with_next_sibling(|n| n.cloned())\n    }\n}\n\nimpl DynamicDomSlot {\n    /// Create a dynamic dom slot that initially represents (\"targets\") the same slot as the\n    /// argument.\n    pub fn new(initial_position: DomSlot) -> Self {\n        Self {\n            target: Rc::new(RefCell::new(initial_position)),\n        }\n    }\n\n    #[cfg(feature = \"hydration\")]\n    pub fn new_debug_trapped() -> Self {\n        Self::new(DomSlot::new_debug_trapped())\n    }\n\n    /// Move out of self, leaving behind a trapped slot. `self` should not be used afterwards.\n    /// Used during the transition from a hydrating to a rendered component to move state between\n    /// enum variants.\n    #[cfg(feature = \"hydration\")]\n    pub fn take(&mut self) -> Self {\n        std::mem::replace(self, Self::new(DomSlot::new_debug_trapped()))\n    }\n\n    /// Change the [`DomSlot`] that is targeted. Subsequently, this will behave as if `self` was\n    /// created from the passed DomSlot in the first place.\n    pub fn reassign(&self, next_position: DomSlot) {\n        // TODO: is not defensive against accidental reference loops\n        *self.target.borrow_mut() = next_position;\n    }\n\n    /// Get a [`DomSlot`] that gets automatically updated when `self` gets reassigned. All such\n    /// slots are equivalent to each other and point to the same position.\n    pub fn to_position(&self) -> DomSlot {\n        DomSlot {\n            variant: DomSlotVariant::Chained(self.clone()),\n        }\n    }\n\n    fn with_next_sibling<R>(&self, f: impl FnOnce(Option<&Node>) -> R) -> R {\n        // we use an iterative approach to traverse a possible long chain for references\n        // see for example issue #3043 why a recursive call is impossible for large lists in vdom\n\n        // TODO: there could be some data structure that performs better here. E.g. a balanced tree\n        // with parent pointers come to mind, but they are a bit fiddly to implement in rust\n        let mut this = self.target.clone();\n        loop {\n            //                          v------- borrow lives for this match expression\n            let next_this = match &this.borrow().variant {\n                DomSlotVariant::Node(ref n) => break f(n.as_ref()),\n                // We clone an Rc here temporarily, so that we don't have to consume stack\n                // space. The alternative would be to keep the\n                // `Ref<'_, DomSlot>` above in some temporary buffer\n                DomSlotVariant::Chained(ref chain) => chain.target.clone(),\n            };\n            this = next_this;\n        }\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod layout_tests {\n    use gloo::utils::document;\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use super::*;\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn new_at_and_get() {\n        let node = document().create_element(\"p\").unwrap();\n        let position = DomSlot::at(node.clone().into());\n        assert_eq!(\n            position.get().unwrap(),\n            node.clone().into(),\n            \"expected the DomSlot to be at {node:#?}\"\n        );\n    }\n\n    #[test]\n    fn new_at_end_and_get() {\n        let position = DomSlot::at_end();\n        assert!(\n            position.get().is_none(),\n            \"expected the DomSlot to not have a next sibling\"\n        );\n    }\n\n    #[test]\n    fn get_through_dynamic() {\n        let original = DomSlot::at(document().create_element(\"p\").unwrap().into());\n        let target = DynamicDomSlot::new(original.clone());\n        assert_eq!(\n            target.to_position().get(),\n            original.get(),\n            \"expected {target:#?} to point to the same position as {original:#?}\"\n        );\n    }\n\n    #[test]\n    fn get_after_reassign() {\n        let target = DynamicDomSlot::new(DomSlot::at_end());\n        let target_pos = target.to_position();\n        // We reassign *after* we called `to_position` here to be strict in the test\n        let replacement = DomSlot::at(document().create_element(\"p\").unwrap().into());\n        target.reassign(replacement.clone());\n        assert_eq!(\n            target_pos.get(),\n            replacement.get(),\n            \"expected {target:#?} to point to the same position as {replacement:#?}\"\n        );\n    }\n\n    #[test]\n    fn get_chain_after_reassign() {\n        let middleman = DynamicDomSlot::new(DomSlot::at_end());\n        let target = DynamicDomSlot::new(middleman.to_position());\n        let target_pos = target.to_position();\n        assert!(\n            target.to_position().get().is_none(),\n            \"should not yet point to a node\"\n        );\n        // Now reassign the middle man, but get the node from `target`\n        let replacement = DomSlot::at(document().create_element(\"p\").unwrap().into());\n        middleman.reassign(replacement.clone());\n        assert_eq!(\n            target_pos.get(),\n            replacement.get(),\n            \"expected {target:#?} to point to the same position as {replacement:#?}\"\n        );\n    }\n\n    #[test]\n    fn debug_printing() {\n        // basic tests that these don't panic. We don't enforce any specific format.\n        println!(\"At end: {:?}\", DomSlot::at_end());\n        println!(\"Trapped: {:?}\", DomSlot::new_debug_trapped());\n        println!(\n            \"At element: {:?}\",\n            DomSlot::at(document().create_element(\"p\").unwrap().into())\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/subtree_root.rs",
    "content": "//! Per-subtree state of apps\n\nuse std::borrow::Cow;\nuse std::cell::RefCell;\nuse std::collections::HashSet;\nuse std::hash::{Hash, Hasher};\nuse std::rc::{Rc, Weak};\nuse std::sync::atomic::{AtomicBool, AtomicU32, Ordering};\n\nuse wasm_bindgen::prelude::{wasm_bindgen, Closure};\nuse wasm_bindgen::{intern, JsCast, UnwrapThrowExt};\nuse web_sys::{\n    AddEventListenerOptions, Element, Event, EventTarget as HtmlEventTarget, ShadowRoot,\n};\n\nuse super::{test_log, Registry};\nuse crate::virtual_dom::{Listener, ListenerKind};\n\n/// DOM-Types that capture (bubbling) events. This generally includes event targets,\n/// but also subtree roots.\npub trait EventGrating {\n    fn subtree_id(&self) -> Option<TreeId>;\n    fn set_subtree_id(&self, tree_id: TreeId);\n    // When caching, we key on the length of the `composed_path`. Important to check\n    // considering event retargeting!\n    fn cache_key(&self) -> Option<u32>;\n    fn set_cache_key(&self, key: u32);\n}\n\n#[wasm_bindgen]\nextern \"C\" {\n    // Duck-typing, not a real class on js-side. On rust-side, use impls of EventGrating below\n    type EventTargetable;\n    #[wasm_bindgen(method, getter = __yew_subtree_id, structural)]\n    fn subtree_id(this: &EventTargetable) -> Option<TreeId>;\n    #[wasm_bindgen(method, setter = __yew_subtree_id, structural)]\n    fn set_subtree_id(this: &EventTargetable, id: TreeId);\n    #[wasm_bindgen(method, getter = __yew_subtree_cache_key, structural)]\n    fn cache_key(this: &EventTargetable) -> Option<u32>;\n    #[wasm_bindgen(method, setter = __yew_subtree_cache_key, structural)]\n    fn set_cache_key(this: &EventTargetable, key: u32);\n}\n\nmacro_rules! impl_event_grating {\n    ($($t:ty);* $(;)?) => {\n        $(\n            impl EventGrating for $t {\n                fn subtree_id(&self) -> Option<TreeId> {\n                    self.unchecked_ref::<EventTargetable>().subtree_id()\n                }\n                fn set_subtree_id(&self, tree_id: TreeId) {\n                    self.unchecked_ref::<EventTargetable>()\n                        .set_subtree_id(tree_id);\n                }\n                fn cache_key(&self) -> Option<u32> {\n                    self.unchecked_ref::<EventTargetable>().cache_key()\n                }\n                fn set_cache_key(&self, key: u32) {\n                    self.unchecked_ref::<EventTargetable>().set_cache_key(key)\n                }\n            }\n        )*\n    }\n}\n\nimpl_event_grating!(\n    HtmlEventTarget;\n    Event; // We cache the found subtree id on the event. This should speed up repeated searches\n);\n\n/// The TreeId is the additional payload attached to each listening element\n/// It identifies the host responsible for the target. Events not matching\n/// are ignored during handling\ntype TreeId = u32;\n\n/// Special id for caching the fact that some event should not be handled\nstatic NONE_TREE_ID: TreeId = 0;\nstatic NEXT_ROOT_ID: AtomicU32 = AtomicU32::new(1);\n\nfn next_root_id() -> TreeId {\n    NEXT_ROOT_ID.fetch_add(1, Ordering::SeqCst)\n}\n\n/// Data kept per controlled subtree. [Portal] and [AppHandle] serve as\n/// hosts. Two controlled subtrees should never overlap.\n///\n/// [Portal]: super::bportal::BPortal\n/// [AppHandle]: super::app_handle::AppHandle\n#[derive(Debug, Clone)]\npub struct BSubtree(Rc<SubtreeData>);\n\n/// The parent is the logical location where a subtree is mounted\n/// Used to bubble events through portals, which are physically somewhere else in the DOM tree\n/// but should bubble to logical ancestors in the virtual DOM tree\n#[derive(Debug)]\nstruct ParentingInformation {\n    parent_root: Rc<SubtreeData>,\n    // Logical parent of the subtree. Might be the host element of another subtree,\n    // if mounted as a direct child, or a controlled element.\n    mount_element: Element,\n}\n\n#[derive(Clone, Hash, Eq, PartialEq, Debug)]\npub struct EventDescriptor {\n    kind: ListenerKind,\n    passive: bool,\n}\n\nimpl From<&dyn Listener> for EventDescriptor {\n    fn from(l: &dyn Listener) -> Self {\n        Self {\n            kind: l.kind(),\n            passive: l.passive(),\n        }\n    }\n}\n\n// FIXME: this is a reproduction of gloo's EventListener to work around #2989\n// change back to gloo's implementation once it has been decided how to fix this upstream\n// The important part is that we use `Fn` instead of `FnMut` below!\ntype EventClosure = Closure<dyn Fn(&Event)>;\n#[derive(Debug)]\n#[must_use = \"event listener will never be called after being dropped\"]\nstruct EventListener {\n    target: HtmlEventTarget,\n    event_type: Cow<'static, str>,\n    callback: Option<EventClosure>,\n}\n\nimpl Drop for EventListener {\n    #[inline]\n    fn drop(&mut self) {\n        if let Some(ref callback) = self.callback {\n            self.target\n                .remove_event_listener_with_callback_and_bool(\n                    &self.event_type,\n                    callback.as_ref().unchecked_ref(),\n                    true, // Always capture\n                )\n                .unwrap_throw();\n        }\n    }\n}\n\nimpl EventListener {\n    fn new(\n        target: &HtmlEventTarget,\n        desc: &EventDescriptor,\n        callback: impl 'static + Fn(&Event),\n    ) -> Self {\n        let event_type = desc.kind.type_name();\n\n        let callback = Closure::wrap(Box::new(callback) as Box<dyn Fn(&Event)>);\n        // defaults: { once: false }\n        let options = AddEventListenerOptions::new();\n        options.set_capture(true);\n        options.set_passive(desc.passive);\n\n        target\n            .add_event_listener_with_callback_and_add_event_listener_options(\n                intern(&event_type),\n                callback.as_ref().unchecked_ref(),\n                &options,\n            )\n            .unwrap_throw();\n\n        EventListener {\n            target: target.clone(),\n            event_type,\n            callback: Some(callback),\n        }\n    }\n\n    #[cfg(not(test))]\n    fn forget(mut self) {\n        if let Some(callback) = self.callback.take() {\n            // Should always match, but no need to introduce a panic path here\n            callback.forget();\n        }\n    }\n}\n\n/// Ensures event handler registration.\n// Separate struct to DRY, while avoiding partial struct mutability.\n#[derive(Debug)]\nstruct HostHandlers {\n    /// The host element where events are registered\n    host: HtmlEventTarget,\n\n    /// Keep track of all listeners to drop them on registry drop.\n    /// The registry is never dropped in production.\n    #[cfg(test)]\n    registered: Vec<(ListenerKind, EventListener)>,\n}\n\nimpl HostHandlers {\n    fn new(host: HtmlEventTarget) -> Self {\n        Self {\n            host,\n            #[cfg(test)]\n            registered: Vec::default(),\n        }\n    }\n\n    fn add_listener(&mut self, desc: &EventDescriptor, callback: impl 'static + Fn(&Event)) {\n        let cl = EventListener::new(&self.host, desc, callback);\n\n        // Never drop the closure as this event handler is static\n        #[cfg(not(test))]\n        cl.forget();\n        #[cfg(test)]\n        self.registered.push((desc.kind.clone(), cl));\n    }\n}\n\n/// Per subtree data\n#[derive(Debug)]\nstruct SubtreeData {\n    /// Data shared between all trees in an app\n    app_data: Rc<RefCell<AppData>>,\n    /// Parent subtree\n    parent: Option<ParentingInformation>,\n\n    subtree_id: TreeId,\n    host: HtmlEventTarget,\n    event_registry: RefCell<Registry>,\n    global: RefCell<HostHandlers>,\n}\n\n#[derive(Debug)]\nstruct WeakSubtree {\n    subtree_id: TreeId,\n    weak_ref: Weak<SubtreeData>,\n}\n\nimpl Hash for WeakSubtree {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.subtree_id.hash(state)\n    }\n}\n\nimpl PartialEq for WeakSubtree {\n    fn eq(&self, other: &Self) -> bool {\n        self.subtree_id == other.subtree_id\n    }\n}\nimpl Eq for WeakSubtree {}\n\n/// Per tree data, shared between all subtrees in the hierarchy\n#[derive(Debug, Default)]\nstruct AppData {\n    subtrees: HashSet<WeakSubtree>,\n    listening: HashSet<EventDescriptor>,\n}\n\nimpl AppData {\n    fn add_subtree(&mut self, subtree: &Rc<SubtreeData>) {\n        for event in self.listening.iter() {\n            subtree.add_listener(event);\n        }\n        self.subtrees.insert(WeakSubtree {\n            subtree_id: subtree.subtree_id,\n            weak_ref: Rc::downgrade(subtree),\n        });\n    }\n\n    fn ensure_handled(&mut self, desc: &EventDescriptor) {\n        if !self.listening.insert(desc.clone()) {\n            return;\n        }\n        self.subtrees.retain(|subtree| {\n            if let Some(subtree) = subtree.weak_ref.upgrade() {\n                subtree.add_listener(desc);\n                true\n            } else {\n                false\n            }\n        })\n    }\n}\n\n/// Bubble events during delegation\nstatic BUBBLE_EVENTS: AtomicBool = AtomicBool::new(true);\n\n/// Set, if events should bubble up the DOM tree, calling any matching callbacks.\n///\n/// Bubbling is enabled by default. Disabling bubbling can lead to substantial improvements in event\n/// handling performance.\n///\n/// This function should be called before any component is mounted.\n#[cfg(feature = \"csr\")]\npub fn set_event_bubbling(bubble: bool) {\n    BUBBLE_EVENTS.store(bubble, Ordering::Relaxed);\n}\n\nstruct BrandingSearchResult {\n    branding: TreeId,\n    closest_branded_ancestor: Element,\n}\n\nfn shadow_aware_parent(el: &Element) -> Option<Element> {\n    match el.parent_element() {\n        s @ Some(_) => s,\n        None => el.parent_node()?.dyn_ref::<ShadowRoot>().map(|h| h.host()),\n    }\n}\n\n/// Deduce the subtree an element is part of. This already partially starts the bubbling\n/// process, as long as no listeners are encountered.\n/// Subtree roots are always branded with their own subtree id.\nfn find_closest_branded_element(mut el: Element, do_bubble: bool) -> Option<BrandingSearchResult> {\n    if !do_bubble {\n        let branding = el.subtree_id()?;\n        Some(BrandingSearchResult {\n            branding,\n            closest_branded_ancestor: el,\n        })\n    } else {\n        let responsible_tree_id = loop {\n            if let Some(tree_id) = el.subtree_id() {\n                break tree_id;\n            }\n            el = shadow_aware_parent(&el)?;\n        };\n        Some(BrandingSearchResult {\n            branding: responsible_tree_id,\n            closest_branded_ancestor: el,\n        })\n    }\n}\n\n/// Iterate over all potentially listening elements in bubbling order.\n/// If bubbling is turned off, yields at most a single element.\nfn start_bubbling_from(\n    subtree: &SubtreeData,\n    root_or_listener: Element,\n    should_bubble: bool,\n) -> impl '_ + Iterator<Item = (&'_ SubtreeData, Element)> {\n    let start = subtree.bubble_to_inner_element(root_or_listener, should_bubble);\n\n    std::iter::successors(start, move |(subtree, element)| {\n        if !should_bubble {\n            return None;\n        }\n        let parent = shadow_aware_parent(element)?;\n        subtree.bubble_to_inner_element(parent, true)\n    })\n}\n\nimpl SubtreeData {\n    fn new_ref(host_element: &HtmlEventTarget, parent: Option<ParentingInformation>) -> Rc<Self> {\n        let tree_root_id = next_root_id();\n        let event_registry = Registry::new();\n        let host_handlers = HostHandlers::new(host_element.clone());\n        let app_data = match parent {\n            Some(ref parent) => parent.parent_root.app_data.clone(),\n            None => Rc::default(),\n        };\n        let subtree = Rc::new(SubtreeData {\n            parent,\n            app_data,\n\n            subtree_id: tree_root_id,\n            host: host_element.clone(),\n            event_registry: RefCell::new(event_registry),\n            global: RefCell::new(host_handlers),\n        });\n        subtree.app_data.borrow_mut().add_subtree(&subtree);\n        subtree\n    }\n\n    fn event_registry(&self) -> &RefCell<Registry> {\n        &self.event_registry\n    }\n\n    fn host_handlers(&self) -> &RefCell<HostHandlers> {\n        &self.global\n    }\n\n    // Bubble a potential parent until it reaches an internal element\n    fn bubble_to_inner_element(\n        &self,\n        parent_el: Element,\n        should_bubble: bool,\n    ) -> Option<(&Self, Element)> {\n        let mut next_subtree = self;\n        let mut next_el = parent_el;\n        if !should_bubble && next_subtree.host.eq(&next_el) {\n            return None;\n        }\n        while next_subtree.host.eq(&next_el) {\n            // we've reached the host, delegate to a parent if one exists\n            let parent = next_subtree.parent.as_ref()?;\n            next_subtree = &parent.parent_root;\n            next_el = parent.mount_element.clone();\n        }\n        Some((next_subtree, next_el))\n    }\n\n    fn start_bubbling_if_responsible<'s>(\n        &'s self,\n        event: &'s Event,\n    ) -> Option<impl 's + Iterator<Item = (&'s SubtreeData, Element)>> {\n        // Note: the event is not necessarily identically the same object for all installed\n        // handlers hence this cache can be unreliable. Hence the cached responsible_tree_id\n        // might be missing. On the other hand, due to event retargeting at shadow roots,\n        // the cache might be wrong! Keep in mind that we handle events in the capture\n        // phase, so top-down. When descending and retargeting into closed shadow-dom, the\n        // event might have been handled 'prematurely'. TODO: figure out how to prevent this\n        // and establish correct event handling for closed shadow root. Note: Other\n        // frameworks also get this wrong and dispatch such events multiple times.\n        let event_path = event.composed_path();\n        let derived_cached_key = event_path.length();\n        let cached_branding = if matches!(event.cache_key(), Some(cache_key) if cache_key == derived_cached_key)\n        {\n            event.subtree_id()\n        } else {\n            None\n        };\n        if matches!(cached_branding, Some(responsible_tree_id) if responsible_tree_id != self.subtree_id)\n        {\n            // some other handler has determined (via this function, but other `self`) a subtree\n            // that is responsible for handling this event, and it's not this subtree.\n            return None;\n        }\n        // We're tasked with finding the subtree that is responsible with handling the event, and/or\n        // run the handling if that's `self`.\n        let target = event_path.get(0).dyn_into::<Element>().ok()?;\n        let should_bubble = BUBBLE_EVENTS.load(Ordering::Relaxed) && event.bubbles();\n        // We say that the most deeply nested subtree is \"responsible\" for handling the event.\n        let (responsible_tree_id, bubbling_start) = if let Some(branding) = cached_branding {\n            (branding, target.clone())\n        } else if let Some(branding) = find_closest_branded_element(target.clone(), should_bubble) {\n            let BrandingSearchResult {\n                branding,\n                closest_branded_ancestor,\n            } = branding;\n            event.set_subtree_id(branding);\n            event.set_cache_key(derived_cached_key);\n            (branding, closest_branded_ancestor)\n        } else {\n            // Possible only? if bubbling is disabled\n            // No tree should handle this event\n            event.set_subtree_id(NONE_TREE_ID);\n            event.set_cache_key(derived_cached_key);\n            return None;\n        };\n        if self.subtree_id != responsible_tree_id {\n            return None;\n        }\n        if self.host.eq(&target) {\n            // One more special case: don't handle events that get fired directly on a subtree host\n            return None;\n        }\n        Some(start_bubbling_from(self, bubbling_start, should_bubble))\n        // # More details: When nesting occurs\n        //\n        // Event listeners are installed only on the subtree roots. Still, those roots can\n        // nest. This could lead to events getting handled multiple times. We want event handling to\n        // start at the most deeply nested subtree.\n        //\n        // A nested subtree portals into an element that is controlled by the user and rendered\n        // with VNode::VRef. We get the following dom nesting:\n        //\n        // AppRoot > .. > UserControlledVRef > .. > NestedTree(PortalExit) > ..\n        // --------------                          ----------------------------\n        // The underlined parts of the hierarchy are controlled by Yew.\n        //\n        // from the following virtual_dom\n        // <AppRoot>\n        //   {VNode::VRef(<div><div id=\"portal_target\" /></div>)}\n        //   {create_portal(<NestedTree />, #portal_target)}\n        // </AppRoot>\n    }\n\n    /// Handle a global event firing\n    fn handle(&self, desc: EventDescriptor, event: Event) {\n        let run_handler = |root: &Self, el: &Element| {\n            let handler = Registry::get_handler(root.event_registry(), el, &desc);\n            if let Some(handler) = handler {\n                handler(&event)\n            }\n        };\n        if let Some(bubbling_it) = self.start_bubbling_if_responsible(&event) {\n            test_log!(\"Running handler on subtree {}\", self.subtree_id);\n            for (subtree, el) in bubbling_it {\n                if event.cancel_bubble() {\n                    break;\n                }\n                run_handler(subtree, &el);\n            }\n        }\n    }\n\n    fn add_listener(self: &Rc<Self>, desc: &EventDescriptor) {\n        let this = self.clone();\n        let listener = {\n            let desc = desc.clone();\n            move |e: &Event| {\n                this.handle(desc.clone(), e.clone());\n            }\n        };\n        self.host_handlers()\n            .borrow_mut()\n            .add_listener(desc, listener);\n    }\n}\n\nimpl BSubtree {\n    fn do_create_root(\n        host_element: &HtmlEventTarget,\n        parent: Option<ParentingInformation>,\n    ) -> Self {\n        let shared_inner = SubtreeData::new_ref(host_element, parent);\n        let root = BSubtree(shared_inner);\n        root.brand_element(host_element);\n        root\n    }\n\n    /// Create a bundle root at the specified host element\n    pub fn create_root(host_element: &HtmlEventTarget) -> Self {\n        Self::do_create_root(host_element, None)\n    }\n\n    /// Create a bundle root at the specified host element, that is logically\n    /// mounted under the specified element in this tree.\n    pub fn create_subroot(&self, mount_point: Element, host_element: &HtmlEventTarget) -> Self {\n        let parent_information = ParentingInformation {\n            parent_root: self.0.clone(),\n            mount_element: mount_point,\n        };\n        Self::do_create_root(host_element, Some(parent_information))\n    }\n\n    /// Ensure the event described is handled on all subtrees\n    pub fn ensure_handled(&self, desc: &EventDescriptor) {\n        self.0.app_data.borrow_mut().ensure_handled(desc);\n    }\n\n    /// Run f with access to global Registry\n    #[inline]\n    pub fn with_listener_registry<R>(&self, f: impl FnOnce(&mut Registry) -> R) -> R {\n        f(&mut self.0.event_registry().borrow_mut())\n    }\n\n    pub fn brand_element(&self, el: &dyn EventGrating) {\n        el.set_subtree_id(self.0.subtree_id);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/traits.rs",
    "content": "use web_sys::Element;\n\nuse super::{BNode, BSubtree, DomSlot};\nuse crate::html::AnyScope;\n\n/// A Reconcile Target.\n///\n/// When a [Reconcilable] is attached, a reconcile target is created to store additional\n/// information.\npub(super) trait ReconcileTarget {\n    /// Remove self from parent.\n    ///\n    /// Parent to detach is `true` if the parent element will also be detached.\n    fn detach(self, root: &BSubtree, parent: &Element, parent_to_detach: bool);\n\n    /// Move elements from one parent to another parent.\n    /// This is for example used by `VSuspense` to preserve component state without detaching\n    /// (which destroys component state).\n    fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot;\n}\n\n/// This trait provides features to update a tree by calculating a difference against another tree.\npub(super) trait Reconcilable {\n    type Bundle: ReconcileTarget;\n\n    /// Attach a virtual node to the DOM tree.\n    ///\n    /// Parameters:\n    /// - `root`: bundle of the subtree root\n    /// - `parent_scope`: the parent `Scope` used for passing messages to the parent `Component`.\n    /// - `parent`: the parent node in the DOM.\n    /// - `slot`: to find where to put the node.\n    ///\n    /// Returns a reference to the newly inserted element.\n    /// The [`DomSlot`] points the first element (if there are multiple nodes created),\n    /// or is the passed in `slot` if there are no element is created.\n    fn attach(\n        self,\n\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n    ) -> (DomSlot, Self::Bundle);\n\n    /// Scoped diff apply to other tree.\n    ///\n    /// Virtual rendering for the node. It uses parent node and existing\n    /// children (virtual and DOM) to check the difference and apply patches to\n    /// the actual DOM representation.\n    ///\n    /// Parameters:\n    /// - `parent_scope`: the parent `Scope` used for passing messages to the parent `Component`.\n    /// - `parent`: the parent node in the DOM.\n    /// - `slot`: the slot in `parent`'s children where to put the node.\n    /// - `bundle`: the node that this node will be replacing in the DOM. This method will remove\n    ///   the `bundle` from the `parent` if it is of the wrong kind, and otherwise reuse it.\n    ///\n    /// Returns a reference to the newly inserted element.\n    fn reconcile_node(\n        self,\n\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot;\n\n    fn reconcile(\n        self,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut Self::Bundle,\n    ) -> DomSlot;\n\n    /// Replace an existing bundle by attaching self and detaching the existing one\n    fn replace(\n        self,\n\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: &Element,\n        slot: DomSlot,\n        bundle: &mut BNode,\n    ) -> DomSlot\n    where\n        Self: Sized,\n        Self::Bundle: Into<BNode>,\n    {\n        let (self_ref, self_) = self.attach(root, parent_scope, parent, slot);\n        let ancestor = std::mem::replace(bundle, self_.into());\n        ancestor.detach(root, parent, false);\n        self_ref\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n    use crate::dom_bundle::{DynamicDomSlot, Fragment};\n\n    pub(in crate::dom_bundle) trait Hydratable: Reconcilable {\n        /// hydrates current tree.\n        ///\n        /// Returns a reference to the first node of the hydrated tree.\n        ///\n        /// # Important\n        ///\n        /// DOM tree is hydrated from top to bottom. This is different than [`Reconcilable`].\n        fn hydrate(\n            self,\n            root: &BSubtree,\n            parent_scope: &AnyScope,\n            parent: &Element,\n            fragment: &mut Fragment,\n            // We hydrate in document order, but need to know the \"next sibling\" in each component\n            // to shift elements. (blame Web API for having `Node.insertBefore` but no\n            // `Node.insertAfter`) Hence, we pass an optional argument to inform of the\n            // new hydrated node's position. This should end up assigning the same\n            // position that would have been returned from `Self::attach` on creation.\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> Self::Bundle;\n    }\n}\n\n#[cfg(feature = \"hydration\")]\npub(in crate::dom_bundle) use feat_hydration::*;\n"
  },
  {
    "path": "packages/yew/src/dom_bundle/utils.rs",
    "content": "#[cfg(all(test, target_arch = \"wasm32\", verbose_tests))]\nmacro_rules! test_log {\n    ($fmt:literal, $($arg:expr),* $(,)?) => {\n        ::wasm_bindgen_test::console_log!(concat!(\"\\t  \", $fmt), $($arg),*);\n    };\n}\n#[cfg(not(all(test, target_arch = \"wasm32\", verbose_tests)))]\nmacro_rules! test_log {\n    ($fmt:literal, $($arg:expr),* $(,)?) => {\n        // Only type-check the format expression, do not run any side effects\n        let _ = || { std::format_args!(concat!(\"\\t  \", $fmt), $($arg),*); };\n    };\n}\n/// Log an operation during tests for debugging purposes\n/// Set RUSTFLAGS=\"--cfg verbose_tests\" environment variable to activate.\npub(super) use test_log;\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use std::borrow::Cow;\n\n    use wasm_bindgen::JsCast;\n    use web_sys::{Element, Node};\n\n    pub(in crate::dom_bundle) fn node_type_str(node: &Node) -> Cow<'static, str> {\n        match node.node_type() {\n            Node::ELEMENT_NODE => {\n                let tag = node\n                    .dyn_ref::<Element>()\n                    .map(|m| m.tag_name().to_lowercase())\n                    .unwrap_or_else(|| \"unknown\".to_owned());\n\n                format!(\"{tag} element node\").into()\n            }\n            Node::ATTRIBUTE_NODE => \"attribute node\".into(),\n            Node::TEXT_NODE => \"text node\".into(),\n            Node::CDATA_SECTION_NODE => \"cdata section node\".into(),\n            Node::ENTITY_REFERENCE_NODE => \"entity reference node\".into(),\n            Node::ENTITY_NODE => \"entity node\".into(),\n            Node::PROCESSING_INSTRUCTION_NODE => \"processing instruction node\".into(),\n            Node::COMMENT_NODE => \"comment node\".into(),\n            Node::DOCUMENT_NODE => \"document node\".into(),\n            Node::DOCUMENT_TYPE_NODE => \"document type node\".into(),\n            Node::DOCUMENT_FRAGMENT_NODE => \"document fragment node\".into(),\n            Node::NOTATION_NODE => \"notation node\".into(),\n            _ => \"unknown node\".into(),\n        }\n    }\n}\n\n#[cfg(feature = \"hydration\")]\npub(super) use feat_hydration::*;\n#[cfg(test)]\n// this is needed because clippy doesn't like the import not being used\n#[allow(unused_imports)]\npub(super) use tests::*;\n\n#[cfg(test)]\nmod tests {\n    #![allow(dead_code)]\n\n    use gloo::utils::document;\n    use web_sys::Element;\n\n    use crate::dom_bundle::{BSubtree, DomSlot};\n    use crate::html::AnyScope;\n    use crate::virtual_dom::vtag::SVG_NAMESPACE;\n\n    pub fn setup_parent() -> (BSubtree, AnyScope, Element) {\n        let scope = AnyScope::test();\n        let parent = document().create_element(\"div\").unwrap();\n        let root = BSubtree::create_root(&parent);\n\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        (root, scope, parent)\n    }\n\n    pub fn setup_parent_svg() -> (BSubtree, AnyScope, Element) {\n        let scope = AnyScope::test();\n        let parent = document()\n            .create_element_ns(Some(SVG_NAMESPACE), \"svg\")\n            .unwrap();\n        let root = BSubtree::create_root(&parent);\n\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        (root, scope, parent)\n    }\n\n    pub const SIBLING_CONTENT: &str = \"END\";\n\n    pub(crate) fn setup_parent_and_sibling() -> (BSubtree, AnyScope, Element, DomSlot) {\n        let scope = AnyScope::test();\n        let parent = document().create_element(\"div\").unwrap();\n        let root = BSubtree::create_root(&parent);\n\n        document().body().unwrap().append_child(&parent).unwrap();\n\n        let end = document().create_text_node(SIBLING_CONTENT);\n        parent.append_child(&end).unwrap();\n        let sibling = DomSlot::at(end.into());\n\n        (root, scope, parent, sibling)\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/mod.rs",
    "content": "mod use_callback;\nmod use_context;\nmod use_effect;\nmod use_force_update;\nmod use_memo;\nmod use_prepared_state;\nmod use_reducer;\nmod use_ref;\nmod use_state;\n\nmod use_transitive_state;\n\npub use use_callback::*;\npub use use_context::*;\npub use use_effect::*;\npub use use_force_update::*;\npub use use_memo::*;\npub use use_prepared_state::*;\npub use use_reducer::*;\npub use use_ref::*;\npub use use_state::*;\npub use use_transitive_state::*;\n\nuse crate::functional::HookContext;\n\n/// A trait that is implemented on hooks.\n///\n/// Hooks are defined via the [`#[hook]`](crate::functional::hook) macro. It provides rewrites to\n/// hook invocations and ensures that hooks can only be called at the top-level of a function\n/// component or a hook. Please refer to its documentation on how to implement hooks.\n#[must_use = \"hooks do nothing unless called inside a `#[hook]` or `#[component]` function\"]\npub trait Hook {\n    /// The return type when a hook is run.\n    type Output;\n\n    /// Runs the hook inside current state, returns output upon completion.\n    fn run(self, ctx: &mut HookContext) -> Self::Output;\n}\n\n/// The blanket implementation of boxed hooks.\n#[doc(hidden)]\n#[allow(missing_debug_implementations, missing_docs)]\npub struct BoxedHook<'hook, T> {\n    inner: Box<dyn 'hook + FnOnce(&mut HookContext) -> T>,\n}\n\nimpl<'hook, T> BoxedHook<'hook, T> {\n    #[allow(missing_docs)]\n    pub fn new(inner: Box<dyn 'hook + FnOnce(&mut HookContext) -> T>) -> Self {\n        Self { inner }\n    }\n}\n\nimpl<T> Hook for BoxedHook<'_, T> {\n    type Output = T;\n\n    fn run(self, ctx: &mut HookContext) -> Self::Output {\n        (self.inner)(ctx)\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_callback.rs",
    "content": "use std::rc::Rc;\n\nuse crate::callback::Callback;\nuse crate::functional::{hook, use_memo};\n\n/// Get a immutable reference to a memoized `Callback`. Its state persists across renders.\n/// It will be recreated only if any of the dependencies changes value.\n///\n/// Memoization means it will only get recreated when provided dependencies update/change.\n/// This is useful when passing callbacks to optimized child components that rely on\n/// PartialEq to prevent unnecessary renders.\n///\n/// # Example\n///\n/// ```rust\n/// # use yew::prelude::*;\n/// #\n/// #[derive(Properties, PartialEq)]\n/// pub struct Props {\n///     pub callback: Callback<String, String>,\n/// }\n///\n/// #[component(MyComponent)]\n/// fn my_component(props: &Props) -> Html {\n///     let greeting = props.callback.emit(\"Yew\".to_string());\n///\n///     html! {\n///         <>{ &greeting }</>\n///     }\n/// }\n///\n/// #[component(UseCallback)]\n/// fn callback() -> Html {\n///     let counter = use_state(|| 0);\n///     let onclick = {\n///         let counter = counter.clone();\n///         Callback::from(move |_| counter.set(*counter + 1))\n///     };\n///\n///     // This callback depends on (), so it's created only once, then MyComponent\n///     // will be rendered only once even when you click the button multiple times.\n///     let callback = use_callback((), move |name, _| format!(\"Hello, {}!\", name));\n///\n///     // It can also be used for events, this callback depends on `counter`.\n///     let oncallback = use_callback(counter.clone(), move |_e, counter| {\n///         let _ = **counter;\n///     });\n///\n///     html! {\n///         <div>\n///             <button {onclick}>{ \"Increment value\" }</button>\n///             <button onclick={oncallback}>{ \"Callback\" }</button>\n///             <p>\n///                 <b>{ \"Current value: \" }</b>\n///                 { *counter }\n///             </p>\n///             <MyComponent {callback} />\n///         </div>\n///     }\n/// }\n/// ```\n#[hook]\npub fn use_callback<IN, OUT, F, D>(deps: D, f: F) -> Callback<IN, OUT>\nwhere\n    IN: 'static,\n    OUT: 'static,\n    F: Fn(IN, &D) -> OUT + 'static,\n    D: PartialEq + 'static,\n{\n    let deps = Rc::new(deps);\n\n    (*use_memo(deps, move |deps| {\n        let deps = deps.clone();\n        let f = move |value: IN| f(value, deps.as_ref());\n        Callback::from(f)\n    }))\n    .clone()\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_context.rs",
    "content": "use std::cell::RefCell;\nuse std::marker::PhantomData;\nuse std::rc::Rc;\n\nuse crate::callback::Callback;\nuse crate::context::ContextHandle;\nuse crate::functional::{Hook, HookContext};\n\n/// Hook for consuming context values in function components.\n/// The context of the type passed as `T` is returned. If there is no such context in scope, `None`\n/// is returned. A component which calls `use_context` will re-render when the data of the context\n/// changes.\n///\n/// More information about contexts and how to define and consume them can be found on [Yew Docs](https://yew.rs/docs/concepts/contexts).\n///\n/// # Example\n///\n/// ```rust\n/// use yew::{ContextProvider, component, html, use_context, use_state, Html};\n///\n///\n/// /// App theme\n/// #[derive(Clone, Debug, PartialEq)]\n/// struct Theme {\n///     foreground: String,\n///     background: String,\n/// }\n///\n/// /// Main component\n/// #[component]\n/// pub fn App() -> Html {\n///     let ctx = use_state(|| Theme {\n///         foreground: \"#000000\".to_owned(),\n///         background: \"#eeeeee\".to_owned(),\n///     });\n///\n///     html! {\n///         // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n///         // so we deref it.\n///         // It derefs to `&Theme`, hence the clone\n///         <ContextProvider<Theme> context={(*ctx).clone()}>\n///             // Every child here and their children will have access to this context.\n///             <Toolbar />\n///         </ContextProvider<Theme>>\n///     }\n/// }\n///\n/// /// The toolbar.\n/// /// This component has access to the context\n/// #[component]\n/// pub fn Toolbar() -> Html {\n///     html! {\n///         <div>\n///             <ThemedButton />\n///         </div>\n///     }\n/// }\n///\n/// /// Button placed in `Toolbar`.\n/// /// As this component is a child of `ThemeContextProvider` in the component tree, it also has access to the context.\n/// #[component]\n/// pub fn ThemedButton() -> Html {\n///     let theme = use_context::<Theme>().expect(\"no ctx found\");\n///\n///     html! {\n///         <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n///             { \"Click me!\" }\n///         </button>\n///     }\n/// }\n/// ```\npub fn use_context<T: Clone + PartialEq + 'static>() -> impl Hook<Output = Option<T>> {\n    struct HookProvider<T: Clone + PartialEq + 'static> {\n        _marker: PhantomData<T>,\n    }\n\n    struct UseContext<T: Clone + PartialEq + 'static> {\n        _handle: Option<ContextHandle<T>>,\n        value: Rc<RefCell<Option<T>>>,\n    }\n\n    impl<T> Hook for HookProvider<T>\n    where\n        T: Clone + PartialEq + 'static,\n    {\n        type Output = Option<T>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let scope = ctx.scope.clone();\n\n            let state = ctx.next_state(move |re_render| -> UseContext<T> {\n                let value_cell: Rc<RefCell<Option<T>>> = Rc::default();\n\n                let (init_value, handle) = {\n                    let value_cell = value_cell.clone();\n\n                    scope.context(Callback::from(move |m| {\n                        *(value_cell.borrow_mut()) = Some(m);\n                        re_render()\n                    }))\n                }\n                .map(|(value, handle)| (Some(value), Some(handle)))\n                .unwrap_or((None, None));\n\n                *(value_cell.borrow_mut()) = init_value;\n\n                UseContext {\n                    _handle: handle,\n                    value: value_cell,\n                }\n            });\n\n            let value = state.value.borrow();\n            value.clone()\n        }\n    }\n\n    HookProvider {\n        _marker: PhantomData,\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_effect.rs",
    "content": "use std::cell::RefCell;\n\nuse crate::functional::{hook, Effect, Hook, HookContext};\n\n/// Trait describing the destructor of [`use_effect`] hook.\npub trait TearDown: Sized + 'static {\n    /// The function that is executed when destructor is called\n    fn tear_down(self);\n}\n\nimpl TearDown for () {\n    fn tear_down(self) {}\n}\n\nimpl<F: FnOnce() + 'static> TearDown for F {\n    fn tear_down(self) {\n        self()\n    }\n}\n\nstruct UseEffectBase<T, F, D>\nwhere\n    F: FnOnce(&T) -> D + 'static,\n    T: 'static,\n    D: TearDown,\n{\n    runner_with_deps: Option<(T, F)>,\n    destructor: Option<D>,\n    deps: Option<T>,\n    effect_changed_fn: fn(Option<&T>, Option<&T>) -> bool,\n}\n\nimpl<T, F, D> Effect for RefCell<UseEffectBase<T, F, D>>\nwhere\n    F: FnOnce(&T) -> D + 'static,\n    T: 'static,\n    D: TearDown,\n{\n    fn rendered(&self) {\n        let mut this = self.borrow_mut();\n\n        if let Some((deps, runner)) = this.runner_with_deps.take() {\n            if !(this.effect_changed_fn)(Some(&deps), this.deps.as_ref()) {\n                return;\n            }\n\n            if let Some(de) = this.destructor.take() {\n                de.tear_down();\n            }\n\n            let new_destructor = runner(&deps);\n\n            this.deps = Some(deps);\n            this.destructor = Some(new_destructor);\n        }\n    }\n}\n\nimpl<T, F, D> Drop for UseEffectBase<T, F, D>\nwhere\n    F: FnOnce(&T) -> D + 'static,\n    T: 'static,\n    D: TearDown,\n{\n    fn drop(&mut self) {\n        if let Some(destructor) = self.destructor.take() {\n            destructor.tear_down()\n        }\n    }\n}\n\nfn use_effect_base<T, D>(\n    runner: impl FnOnce(&T) -> D + 'static,\n    deps: T,\n    effect_changed_fn: fn(Option<&T>, Option<&T>) -> bool,\n) -> impl Hook<Output = ()>\nwhere\n    T: 'static,\n    D: TearDown,\n{\n    struct HookProvider<T, F, D>\n    where\n        F: FnOnce(&T) -> D + 'static,\n        T: 'static,\n        D: TearDown,\n    {\n        runner: F,\n        deps: T,\n        effect_changed_fn: fn(Option<&T>, Option<&T>) -> bool,\n    }\n\n    impl<T, F, D> Hook for HookProvider<T, F, D>\n    where\n        F: FnOnce(&T) -> D + 'static,\n        T: 'static,\n        D: TearDown,\n    {\n        type Output = ();\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let Self {\n                runner,\n                deps,\n                effect_changed_fn,\n            } = self;\n\n            let state = ctx.next_effect(|_| -> RefCell<UseEffectBase<T, F, D>> {\n                RefCell::new(UseEffectBase {\n                    runner_with_deps: None,\n                    destructor: None,\n                    deps: None,\n                    effect_changed_fn,\n                })\n            });\n\n            state.borrow_mut().runner_with_deps = Some((deps, runner));\n        }\n    }\n\n    HookProvider {\n        runner,\n        deps,\n        effect_changed_fn,\n    }\n}\n\n/// `use_effect` is used for hooking into the component's lifecycle and creating side effects.\n///\n/// The callback is called every time after the component's render has finished.\n///\n/// # Example\n///\n/// ```rust\n/// use yew::prelude::*;\n/// # use std::rc::Rc;\n///\n/// #[component(UseEffect)]\n/// fn effect() -> Html {\n///     let counter = use_state(|| 0);\n///\n///     let counter_one = counter.clone();\n///     use_effect(move || {\n///         // Make a call to DOM API after component is rendered\n///         gloo::utils::document().set_title(&format!(\"You clicked {} times\", *counter_one));\n///\n///         // Perform the cleanup\n///         || gloo::utils::document().set_title(&format!(\"You clicked 0 times\"))\n///     });\n///\n///     let onclick = {\n///         let counter = counter.clone();\n///         Callback::from(move |_| counter.set(*counter + 1))\n///     };\n///\n///     html! {\n///         <button {onclick}>{ format!(\"Increment to {}\", *counter) }</button>\n///     }\n/// }\n/// ```\n///\n/// # Destructor\n///\n/// Any type implementing [`TearDown`] can be used as destructor, which is called when the component\n/// is re-rendered\n///\n/// ## Tip\n///\n/// The callback can return [`()`] if there is no destructor to run.\n#[hook]\npub fn use_effect<F, D>(f: F)\nwhere\n    F: FnOnce() -> D + 'static,\n    D: TearDown,\n{\n    use_effect_base(|_| f(), (), |_, _| true);\n}\n\n/// This hook is similar to [`use_effect`] but it accepts dependencies.\n///\n/// Whenever the dependencies are changed, the effect callback is called again.\n/// To detect changes, dependencies must implement [`PartialEq`].\n///\n/// # Note\n/// The destructor also runs when dependencies change.\n///\n/// # Example\n///\n/// ```rust\n/// use yew::{component, html, use_effect_with, Html, Properties};\n/// # use gloo::console::log;\n///\n/// #[derive(Properties, PartialEq)]\n/// pub struct Props {\n///     pub is_loading: bool,\n/// }\n///\n/// #[component]\n/// fn HelloWorld(props: &Props) -> Html {\n///     let is_loading = props.is_loading.clone();\n///\n///     use_effect_with(is_loading, move |_| {\n///         log!(\" Is loading prop changed!\");\n///     });\n///\n///     html! {\n///         <>{\"Am I loading? - \"}{is_loading}</>\n///     }\n/// }\n/// ```\n///\n/// # Tips\n///\n/// ## Only on first render\n///\n/// Provide a empty tuple `()` as dependencies when you need to do something only on the first\n/// render of a component.\n///\n/// ```rust\n/// use yew::{component, html, use_effect_with, Html};\n/// # use gloo::console::log;\n///\n/// #[component]\n/// fn HelloWorld() -> Html {\n///     use_effect_with((), move |_| {\n///         log!(\"I got rendered, yay!\");\n///     });\n///\n///     html! { \"Hello\" }\n/// }\n/// ```\n///\n/// ## On destructing or last render\n///\n/// Use [Only on first render](#only-on-first-render) but put the code in the cleanup function.\n/// It will only get called when the component is removed from view / gets destroyed.\n///\n/// ```rust\n/// use yew::{component, html, use_effect_with, Html};\n/// # use gloo::console::log;\n///\n/// #[component]\n/// fn HelloWorld() -> Html {\n///     use_effect_with((), move |_| {\n///         || {\n///             log!(\"Nooo dont kill me, ahhh!\");\n///         }\n///     });\n///\n///     html! { \"Hello\" }\n/// }\n/// ```\n///\n/// Any type implementing [`TearDown`] can be used as destructor\n///\n/// ### Tip\n///\n/// The callback can return [`()`] if there is no destructor to run.\npub fn use_effect_with<T, F, D>(deps: T, f: F) -> impl Hook<Output = ()>\nwhere\n    T: PartialEq + 'static,\n    F: FnOnce(&T) -> D + 'static,\n    D: TearDown,\n{\n    use_effect_base(f, deps, |lhs, rhs| lhs != rhs)\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_force_update.rs",
    "content": "use std::fmt;\n\nuse super::{Hook, HookContext};\nuse crate::functional::ReRender;\n\n/// A handle which can be used to force a re-render of the associated\n/// function component.\n#[derive(Clone)]\npub struct UseForceUpdateHandle {\n    trigger: ReRender,\n}\n\nimpl fmt::Debug for UseForceUpdateHandle {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"UseForceUpdate\").finish()\n    }\n}\n\nimpl UseForceUpdateHandle {\n    /// Trigger an unconditional re-render of the associated function component\n    pub fn force_update(&self) {\n        (self.trigger)()\n    }\n}\n\n#[cfg(nightly_yew)]\nmod feat_nightly {\n    use super::*;\n\n    impl FnOnce<()> for UseForceUpdateHandle {\n        type Output = ();\n\n        extern \"rust-call\" fn call_once(self, _args: ()) -> Self::Output {\n            self.force_update()\n        }\n    }\n\n    impl FnMut<()> for UseForceUpdateHandle {\n        extern \"rust-call\" fn call_mut(&mut self, _args: ()) -> Self::Output {\n            self.force_update()\n        }\n    }\n\n    impl Fn<()> for UseForceUpdateHandle {\n        extern \"rust-call\" fn call(&self, _args: ()) -> Self::Output {\n            self.force_update()\n        }\n    }\n}\n\n/// This hook is used to manually force a function component to re-render.\n///\n/// # Note\n///\n/// Often, using this hook means that you're doing something wrong.\n/// Try to use more specialized hooks, such as [`use_state`] and [`use_reducer`].\n/// This hook should only be used when your component depends on external state where you\n/// can't subscribe to changes, or as a low-level primitive to enable such a subscription-based\n/// approach.\n///\n/// # Use-case\n///\n/// Use this hook when wrapping an API that doesn't expose precise subscription events for fetched\n/// data. You could then, at some point, invalidate your local cache of the fetched data and trigger\n/// a re-render to let the normal render flow of components tell you again which data to fetch, and\n/// repopulate the cache accordingly.\n///\n/// A large externally managed cache, such as a app-wide cache for GraphQL data\n/// should not rerender every component whenever new data arrives, but only those where a query\n/// changed.\n///\n/// If the state of your component is not shared, you should need to use this hook.\n///\n/// # Example\n///\n/// This example implements a silly, manually updated display of the current time. The component\n/// is re-rendered every time the button is clicked. You should usually use a timeout and\n/// `use_state` to automatically trigger a re-render every second without having to use this hook.\n///\n/// ```rust\n/// use yew::prelude::*;\n///\n/// #[component]\n/// fn ManuallyUpdatedDate() -> Html {\n///     let trigger = use_force_update();\n///     let onclick = use_state(move || Callback::from(move |_| trigger.force_update()));\n///     let last_update = js_sys::Date::new_0().to_utc_string();\n///     html! {\n///         <div>\n///             <button onclick={&*onclick}>{\"Update now!\"}</button>\n///             <p>{\"Last updated: \"}{last_update}</p>\n///         </div>\n///     }\n/// }\n/// ```\n///\n/// [`use_state`]: super::use_state()\n/// [`use_reducer`]: super::use_reducer()\npub fn use_force_update() -> impl Hook<Output = UseForceUpdateHandle> {\n    struct UseRerenderHook;\n\n    impl Hook for UseRerenderHook {\n        type Output = UseForceUpdateHandle;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            UseForceUpdateHandle {\n                trigger: ctx.re_render.clone(),\n            }\n        }\n    }\n\n    UseRerenderHook\n}\n\n#[cfg(all(test, nightly_yew))]\nmod nightly_test {\n    use yew::prelude::*;\n\n    #[component]\n    fn ManuallyUpdatedDate() -> Html {\n        let trigger = use_force_update();\n        let _ = move || trigger();\n        html! {}\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_memo.rs",
    "content": "use std::borrow::Borrow;\nuse std::rc::Rc;\n\nuse super::use_mut_ref;\nuse crate::functional::hook;\n\n/// Get a immutable reference to a memoized value.\n///\n/// This version allows for a key cache key derivation that only borrows\n/// like the original argument. For example, using ` K = Rc<D>`, we only\n/// create a shared reference to dependencies *after* they change.\n#[hook]\npub(crate) fn use_memo_base<T, F, D, K>(f: F, deps: D) -> Rc<T>\nwhere\n    T: 'static,\n    F: FnOnce(D) -> (T, K),\n    K: 'static + Borrow<D>,\n    D: PartialEq,\n{\n    struct MemoState<T, K> {\n        memo_key: K,\n        result: Rc<T>,\n    }\n    let state = use_mut_ref(|| -> Option<MemoState<T, K>> { None });\n\n    let mut state = state.borrow_mut();\n    match &*state {\n        Some(existing) if existing.memo_key.borrow() != &deps => {\n            // Drop old state if it's outdated\n            *state = None;\n        }\n        _ => {}\n    };\n    let state = state.get_or_insert_with(|| {\n        let (result, memo_key) = f(deps);\n        let result = Rc::new(result);\n        MemoState { result, memo_key }\n    });\n    state.result.clone()\n}\n\n/// Get a immutable reference to a memoized value.\n///\n/// Memoization means it will only get recalculated when provided dependencies update/change.\n///\n/// It can be useful for keeping things in scope for the lifetime of the component,\n/// so long as you don't store a clone of the resulting `Rc` anywhere that outlives the component.\n///\n/// # Example\n///\n/// ```rust\n/// use yew::prelude::*;\n///\n/// #[derive(PartialEq, Properties)]\n/// pub struct Props {\n///     pub step: usize,\n/// }\n///\n/// #[component(UseMemo)]\n/// fn memo(props: &Props) -> Html {\n///     // Will only get recalculated if `props.step` value changes\n///     let message = use_memo(props.step, |step| {\n///         format!(\"{}. Do Some Expensive Calculation\", step)\n///     });\n///\n///     html! {\n///         <div>\n///             <span>{ (*message).clone() }</span>\n///         </div>\n///     }\n/// }\n/// ```\n#[hook]\npub fn use_memo<T, F, D>(deps: D, f: F) -> Rc<T>\nwhere\n    T: 'static,\n    F: FnOnce(&D) -> T,\n    D: 'static + PartialEq,\n{\n    use_memo_base(|d| (f(&d), d), deps)\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_prepared_state/feat_hydration.rs",
    "content": "//! The client-side rendering variant. This is used for client side rendering.\n\nuse std::marker::PhantomData;\nuse std::rc::Rc;\n\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\nuse wasm_bindgen::JsValue;\n\nuse super::PreparedStateBase;\nuse crate::functional::{use_state, Hook, HookContext};\nuse crate::platform::spawn_local;\nuse crate::suspense::{Suspension, SuspensionResult};\n\n#[cfg(all(\n    target_arch = \"wasm32\",\n    not(target_os = \"wasi\"),\n    not(feature = \"not_browser_env\")\n))]\nasync fn decode_base64(s: &str) -> Result<Vec<u8>, JsValue> {\n    use gloo::utils::window;\n    use js_sys::Uint8Array;\n    use wasm_bindgen::JsCast;\n    use wasm_bindgen_futures::JsFuture;\n\n    let fetch_promise = window().fetch_with_str(s);\n\n    let content_promise = JsFuture::from(fetch_promise)\n        .await\n        .and_then(|m| m.dyn_into::<web_sys::Response>())\n        .and_then(|m| m.array_buffer())?;\n\n    let content_array = JsFuture::from(content_promise)\n        .await\n        .as_ref()\n        .map(Uint8Array::new)?;\n\n    Ok(content_array.to_vec())\n}\n\n#[cfg(any(\n    not(target_arch = \"wasm32\"),\n    target_os = \"wasi\",\n    feature = \"not_browser_env\"\n))]\nasync fn decode_base64(_s: &str) -> Result<Vec<u8>, JsValue> {\n    unreachable!(\"this function is not callable under non-wasm targets!\");\n}\n\n#[doc(hidden)]\npub fn use_prepared_state<T, D>(deps: D) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n{\n    struct HookProvider<T, D>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n    {\n        _marker: PhantomData<T>,\n        deps: D,\n    }\n\n    impl<T, D> Hook for HookProvider<T, D>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let data = use_state(|| {\n                let (s, handle) = Suspension::new();\n                (\n                    SuspensionResult::<(Option<Rc<T>>, Option<Rc<D>>)>::Err(s),\n                    Some(handle),\n                )\n            })\n            .run(ctx);\n\n            let state = {\n                let data = data.clone();\n                ctx.next_prepared_state(move |_re_render, buf| -> PreparedStateBase<T, D> {\n                    if let Some(buf) = buf {\n                        let buf = format!(\"data:application/octet-binary;base64,{buf}\");\n\n                        spawn_local(async move {\n                            let buf = decode_base64(&buf)\n                                .await\n                                .expect(\"failed to deserialize state\");\n\n                            let ((state, deps), _) =\n                                bincode::serde::decode_from_slice::<(Option<T>, Option<D>), _>(\n                                    &buf,\n                                    bincode::config::standard(),\n                                )\n                                .map(|((state, deps), consumed)| {\n                                    ((state.map(Rc::new), deps.map(Rc::new)), consumed)\n                                })\n                                .expect(\"failed to deserialize state\");\n\n                            data.set((Ok((state, deps)), None));\n                        });\n                    }\n\n                    PreparedStateBase {\n                        #[cfg(feature = \"ssr\")]\n                        state: None,\n                        #[cfg(feature = \"ssr\")]\n                        deps: None,\n\n                        has_buf: buf.is_some(),\n                        _marker: PhantomData,\n                    }\n                })\n            };\n\n            if state.has_buf {\n                let (data, deps) = data.0.clone()?;\n\n                if deps.as_deref() == Some(&self.deps) {\n                    return Ok(data);\n                }\n            }\n\n            Ok(None)\n        }\n    }\n\n    HookProvider::<T, D> {\n        _marker: PhantomData,\n        deps,\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_prepared_state/feat_hydration_ssr.rs",
    "content": "//! The client-and-server-side rendering variant.\n\nuse std::future::Future;\nuse std::rc::Rc;\n\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\n\nuse super::{feat_hydration, feat_ssr};\nuse crate::functional::{Hook, HookContext};\nuse crate::html::RenderMode;\nuse crate::suspense::SuspensionResult;\n\n#[doc(hidden)]\npub fn use_prepared_state<T, D, F>(\n    deps: D,\n    f: F,\n) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: FnOnce(Rc<D>) -> T,\n{\n    struct HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> T,\n    {\n        deps: D,\n        f: F,\n    }\n\n    impl<T, D, F> Hook for HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> T,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            match ctx.creation_mode {\n                RenderMode::Ssr => feat_ssr::use_prepared_state(self.deps, self.f).run(ctx),\n                _ => feat_hydration::use_prepared_state(self.deps).run(ctx),\n            }\n        }\n    }\n\n    HookProvider::<T, D, F> { deps, f }\n}\n\n#[doc(hidden)]\npub fn use_prepared_state_with_suspension<T, D, F, U>(\n    deps: D,\n    f: F,\n) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: FnOnce(Rc<D>) -> U,\n    U: 'static + Future<Output = T>,\n{\n    struct HookProvider<T, D, F, U>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> U,\n        U: 'static + Future<Output = T>,\n    {\n        deps: D,\n        f: F,\n    }\n\n    impl<T, D, F, U> Hook for HookProvider<T, D, F, U>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> U,\n        U: 'static + Future<Output = T>,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            match ctx.creation_mode {\n                RenderMode::Ssr => {\n                    feat_ssr::use_prepared_state_with_suspension(self.deps, self.f).run(ctx)\n                }\n                _ => feat_hydration::use_prepared_state(self.deps).run(ctx),\n            }\n        }\n    }\n\n    HookProvider::<T, D, F, U> { deps, f }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_prepared_state/feat_none.rs",
    "content": "//! The noop variant. This is used for client side rendering when hydration is disabled.\n\nuse std::rc::Rc;\n\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\n\nuse crate::hook;\nuse crate::suspense::SuspensionResult;\n\n#[doc(hidden)]\n#[hook]\npub fn use_prepared_state<T, D>(_deps: D) -> SuspensionResult<Option<Rc<T>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n{\n    Ok(None)\n}\n\n#[doc(hidden)]\n#[hook]\npub fn use_prepared_state_with_suspension<T, D>(_deps: D) -> SuspensionResult<Option<Rc<T>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n{\n    Ok(None)\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_prepared_state/feat_ssr.rs",
    "content": "//! The server-side rendering variant. This is used for server side rendering.\n\nuse std::future::Future;\nuse std::marker::PhantomData;\nuse std::rc::Rc;\n\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\n\nuse super::PreparedStateBase;\nuse crate::functional::{use_memo, use_state, Hook, HookContext};\nuse crate::platform::spawn_local;\nuse crate::suspense::{Suspension, SuspensionResult};\n\n#[doc(hidden)]\npub fn use_prepared_state<T, D, F>(\n    deps: D,\n    f: F,\n) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: FnOnce(Rc<D>) -> T,\n{\n    struct HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> T,\n    {\n        deps: D,\n        f: F,\n    }\n\n    impl<T, D, F> Hook for HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> T,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let f = self.f;\n            let deps = Rc::new(self.deps);\n\n            let state = {\n                let deps = deps.clone();\n                use_memo((), move |_| f(deps)).run(ctx)\n            };\n\n            let state = PreparedStateBase {\n                state: Some(state),\n                deps: Some(deps),\n                #[cfg(feature = \"hydration\")]\n                has_buf: true,\n                _marker: PhantomData,\n            };\n\n            let state =\n                ctx.next_prepared_state(|_re_render, _| -> PreparedStateBase<T, D> { state });\n\n            Ok(state.state.clone())\n        }\n    }\n\n    HookProvider::<T, D, F> { deps, f }\n}\n\n#[doc(hidden)]\npub fn use_prepared_state_with_suspension<T, D, F, U>(\n    deps: D,\n    f: F,\n) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: FnOnce(Rc<D>) -> U,\n    U: 'static + Future<Output = T>,\n{\n    struct HookProvider<T, D, F, U>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> U,\n        U: 'static + Future<Output = T>,\n    {\n        deps: D,\n        f: F,\n    }\n\n    impl<T, D, F, U> Hook for HookProvider<T, D, F, U>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: FnOnce(Rc<D>) -> U,\n        U: 'static + Future<Output = T>,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let f = self.f;\n            let deps = Rc::new(self.deps);\n\n            let result = use_state(|| {\n                let (s, handle) = Suspension::new();\n                (Err(s), Some(handle))\n            })\n            .run(ctx);\n\n            {\n                let deps = deps.clone();\n                let result = result.clone();\n                use_state(move || {\n                    let state_f = f(deps.clone());\n\n                    spawn_local(async move {\n                        let state = state_f.await;\n                        result.set((Ok(Rc::new(state)), None));\n                    })\n                })\n                .run(ctx);\n            }\n\n            let state = result.0.clone()?;\n\n            let state = PreparedStateBase {\n                state: Some(state),\n                deps: Some(deps),\n                #[cfg(feature = \"hydration\")]\n                has_buf: true,\n                _marker: PhantomData,\n            };\n\n            let state =\n                ctx.next_prepared_state(|_re_render, _| -> PreparedStateBase<T, D> { state });\n\n            Ok(state.state.clone())\n        }\n    }\n\n    HookProvider::<T, D, F, U> { deps, f }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_prepared_state/mod.rs",
    "content": "#[cfg(feature = \"hydration\")]\npub(super) mod feat_hydration;\n#[cfg(all(feature = \"hydration\", feature = \"ssr\"))]\nmod feat_hydration_ssr;\n#[cfg(not(any(feature = \"hydration\", feature = \"ssr\")))]\npub(super) mod feat_none;\n#[cfg(feature = \"ssr\")]\nmod feat_ssr;\n\n#[cfg(all(feature = \"hydration\", not(feature = \"ssr\")))]\npub use feat_hydration::*;\n#[cfg(all(feature = \"ssr\", feature = \"hydration\"))]\npub use feat_hydration_ssr::*;\n#[cfg(not(any(feature = \"hydration\", feature = \"ssr\")))]\npub use feat_none::*;\n#[cfg(all(feature = \"ssr\", not(feature = \"hydration\")))]\npub use feat_ssr::*;\n/// Use a state prepared on the server side and its value is sent to the client side during\n/// hydration.\n///\n/// The component sees the same value on the server side and client side if the component is\n/// hydrated.\n///\n/// It accepts a closure as the second argument and its dependency value as the first argument.\n/// It returns `SuspensionResult<Option<Rc<T>>>`.\n///\n/// During hydration, it will only return `Ok(Some(Rc<T>))` if the component is hydrated from a\n/// server-side rendering artifact and its dependency value matches.\n///\n/// `let state = use_prepared_state!(deps, |deps| -> ReturnType { ... })?;`\n///\n/// It has the following signature:\n///\n/// ```\n/// # use serde::de::DeserializeOwned;\n/// # use serde::Serialize;\n/// # use std::rc::Rc;\n/// use yew::prelude::*;\n/// use yew::suspense::SuspensionResult;\n///\n/// #[hook]\n/// pub fn use_prepared_state<T, D, F>(deps: D, f: F) -> SuspensionResult<Option<Rc<T>>>\n/// where\n///     D: Serialize + DeserializeOwned + PartialEq + 'static,\n///     T: Serialize + DeserializeOwned + 'static,\n///     F: FnOnce(Rc<D>) -> T,\n/// # { todo!() }\n/// ```\n///\n/// The first argument can also be an async closure\n///\n/// `let state = use_prepared_state!(deps, async |deps| -> ReturnType { ... })?;`\n///\n/// When accepting an async closure, it has the following signature:\n///\n/// ```\n/// # use serde::de::DeserializeOwned;\n/// # use serde::Serialize;\n/// # use std::rc::Rc;\n/// # use std::future::Future;\n/// use yew::prelude::*;\n/// use yew::suspense::SuspensionResult;\n///\n/// #[hook]\n/// pub fn use_prepared_state<T, D, F, U>(\n///         deps: D,\n///         f: F,\n///     ) -> SuspensionResult<Option<Rc<T>>>\n///     where\n///         D: Serialize + DeserializeOwned + PartialEq + 'static,\n///         T: Serialize + DeserializeOwned + 'static,\n///         F: FnOnce(Rc<D>) -> U,\n///         U: 'static + Future<Output = T>,\n/// # { todo!() }\n/// ```\n///\n/// During server-side rendering, a value of type `T` will be calculated from the first\n/// closure.\n///\n/// If the bundle is compiled without server-side rendering, the closure will be stripped\n/// automatically.\n///\n/// # Note\n///\n/// You MUST denote the return type of the closure with `|deps| -> ReturnType { ... }`. This\n/// type is used during client side rendering to deserialize the state prepared on the server\n/// side.\npub use use_prepared_state_macro as use_prepared_state;\n// With SSR.\n#[doc(hidden)]\n#[cfg(feature = \"ssr\")]\npub use yew_macro::use_prepared_state_with_closure as use_prepared_state_macro;\n// Without SSR.\n#[doc(hidden)]\n#[cfg(not(feature = \"ssr\"))]\npub use yew_macro::use_prepared_state_without_closure as use_prepared_state_macro;\n\n#[cfg(any(feature = \"hydration\", feature = \"ssr\"))]\nmod feat_any_hydration_ssr {\n    use std::marker::PhantomData;\n    #[cfg(feature = \"ssr\")]\n    use std::rc::Rc;\n\n    use serde::de::DeserializeOwned;\n    use serde::Serialize;\n\n    use crate::functional::PreparedState;\n\n    pub(super) struct PreparedStateBase<T, D>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n    {\n        #[cfg(feature = \"ssr\")]\n        pub state: Option<Rc<T>>,\n        #[cfg(feature = \"ssr\")]\n        pub deps: Option<Rc<D>>,\n        #[cfg(feature = \"hydration\")]\n        pub has_buf: bool,\n        pub _marker: PhantomData<(T, D)>,\n    }\n\n    impl<T, D> PreparedState for PreparedStateBase<T, D>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n    {\n        #[cfg(feature = \"ssr\")]\n        fn prepare(&self) -> String {\n            use base64ct::{Base64, Encoding};\n\n            let state = bincode::serde::encode_to_vec(\n                (self.state.as_deref(), self.deps.as_deref()),\n                bincode::config::standard(),\n            )\n            .expect(\"failed to prepare state\");\n\n            Base64::encode_string(&state)\n        }\n    }\n}\n\n#[cfg(any(feature = \"hydration\", feature = \"ssr\"))]\nuse feat_any_hydration_ssr::PreparedStateBase;\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_reducer.rs",
    "content": "use std::cell::RefCell;\nuse std::fmt;\nuse std::marker::PhantomData;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse implicit_clone::ImplicitClone;\n\nuse crate::functional::{hook, Hook, HookContext};\nuse crate::html::IntoPropValue;\nuse crate::Callback;\n\ntype DispatchFn<T> = Rc<dyn Fn(<T as Reducible>::Action)>;\n\n/// A trait that implements a reducer function of a type.\npub trait Reducible {\n    /// The action type of the reducer.\n    type Action;\n\n    /// The reducer function.\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self>;\n}\n\nstruct UseReducer<T>\nwhere\n    T: Reducible,\n{\n    current_state: Rc<RefCell<Rc<T>>>,\n\n    dispatch: DispatchFn<T>,\n}\n\n/// State handle for [`use_reducer`] and [`use_reducer_eq`] hook\npub struct UseReducerHandle<T>\nwhere\n    T: Reducible,\n{\n    /// Shared source of truth, updated synchronously by dispatch.\n    current_state: Rc<RefCell<Rc<T>>>,\n    /// Accumulates `Rc<T>` clones returned by [`Deref::deref`] so that references\n    /// remain valid for the lifetime of this handle. Reset on each re-render when\n    /// a new handle is created.\n    deref_history: RefCell<Vec<Rc<T>>>,\n    dispatch: DispatchFn<T>,\n}\n\nimpl<T> UseReducerHandle<T>\nwhere\n    T: Reducible,\n{\n    /// Dispatch the given action to the reducer.\n    pub fn dispatch(&self, value: T::Action) {\n        (self.dispatch)(value)\n    }\n\n    /// Returns the dispatcher of the current state.\n    pub fn dispatcher(&self) -> UseReducerDispatcher<T> {\n        UseReducerDispatcher {\n            dispatch: self.dispatch.clone(),\n        }\n    }\n}\n\nimpl<T> Deref for UseReducerHandle<T>\nwhere\n    T: Reducible,\n{\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        let rc = match self.current_state.try_borrow() {\n            Ok(shared) => Rc::clone(&*shared),\n            Err(_) => {\n                // RefCell is mutably borrowed (during dispatch). Use the last\n                // value we successfully read.\n                let history = self.deref_history.borrow();\n                Rc::clone(history.last().expect(\"deref_history is never empty\"))\n            }\n        };\n\n        let ptr: *const T = Rc::as_ptr(&rc);\n\n        // Only store a new entry when the Rc allocation differs from the most\n        // recent one, avoiding unbounded growth from repeated reads of the same\n        // state.\n        {\n            let mut history = self.deref_history.borrow_mut();\n            if !Rc::ptr_eq(history.last().expect(\"deref_history is never empty\"), &rc) {\n                history.push(rc);\n            }\n        }\n\n        // SAFETY: `ptr` points into the heap allocation of an `Rc<T>`. That Rc\n        // is kept alive in `self.deref_history` (either the entry we just pushed,\n        // or a previous entry with the same allocation). `deref_history` lives as\n        // long as `self`, and `Rc` guarantees its heap allocation stays live while\n        // any clone exists. Therefore `ptr` is valid for the lifetime of `&self`.\n        unsafe { &*ptr }\n    }\n}\n\nimpl<T> Clone for UseReducerHandle<T>\nwhere\n    T: Reducible,\n{\n    fn clone(&self) -> Self {\n        // Take a fresh snapshot so the clone's deref_history is never empty.\n        let snapshot = match self.current_state.try_borrow() {\n            Ok(shared) => Rc::clone(&*shared),\n            Err(_) => {\n                let history = self.deref_history.borrow();\n                Rc::clone(history.last().expect(\"deref_history is never empty\"))\n            }\n        };\n        Self {\n            current_state: Rc::clone(&self.current_state),\n            deref_history: RefCell::new(vec![snapshot]),\n            dispatch: Rc::clone(&self.dispatch),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for UseReducerHandle<T>\nwhere\n    T: Reducible + fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let value = if let Ok(rc_ref) = self.current_state.try_borrow() {\n            format!(\"{:?}\", *rc_ref)\n        } else {\n            let history = self.deref_history.borrow();\n            format!(\n                \"{:?}\",\n                **history.last().expect(\"deref_history is never empty\")\n            )\n        };\n        f.debug_struct(\"UseReducerHandle\")\n            .field(\"value\", &value)\n            .finish()\n    }\n}\n\nimpl<T> PartialEq for UseReducerHandle<T>\nwhere\n    T: Reducible + PartialEq,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        let self_snapshot = self.deref_history.borrow();\n        let rhs_snapshot = rhs.deref_history.borrow();\n        *self_snapshot[0] == *rhs_snapshot[0]\n    }\n}\n\nimpl<T> ImplicitClone for UseReducerHandle<T> where T: Reducible {}\n\n/// Dispatcher handle for [`use_reducer`] and [`use_reducer_eq`] hook\npub struct UseReducerDispatcher<T>\nwhere\n    T: Reducible,\n{\n    dispatch: DispatchFn<T>,\n}\n\nimpl<T> Clone for UseReducerDispatcher<T>\nwhere\n    T: Reducible,\n{\n    fn clone(&self) -> Self {\n        Self {\n            dispatch: Rc::clone(&self.dispatch),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for UseReducerDispatcher<T>\nwhere\n    T: Reducible + fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"UseReducerDispatcher\").finish()\n    }\n}\n\nimpl<T> PartialEq for UseReducerDispatcher<T>\nwhere\n    T: Reducible,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        // We are okay with comparisons from different compilation units to result in false\n        // not-equal results. This should only lead in the worst-case to some unneeded\n        // re-renders.\n        #[allow(ambiguous_wide_pointer_comparisons)]\n        Rc::ptr_eq(&self.dispatch, &rhs.dispatch)\n    }\n}\n\nimpl<T> ImplicitClone for UseReducerDispatcher<T> where T: Reducible {}\n\nimpl<T> From<UseReducerDispatcher<T>> for Callback<<T as Reducible>::Action>\nwhere\n    T: Reducible,\n{\n    fn from(val: UseReducerDispatcher<T>) -> Self {\n        Callback { cb: val.dispatch }\n    }\n}\n\nimpl<T> IntoPropValue<Callback<<T as Reducible>::Action>> for UseReducerDispatcher<T>\nwhere\n    T: Reducible,\n{\n    fn into_prop_value(self) -> Callback<<T as Reducible>::Action> {\n        Callback { cb: self.dispatch }\n    }\n}\n\nimpl<T> UseReducerDispatcher<T>\nwhere\n    T: Reducible,\n{\n    /// Dispatch the given action to the reducer.\n    pub fn dispatch(&self, value: T::Action) {\n        (self.dispatch)(value)\n    }\n\n    /// Get a callback, invoking which is equivalent to calling `dispatch()`\n    /// on this same dispatcher.\n    pub fn to_callback(&self) -> Callback<<T as Reducible>::Action> {\n        Callback {\n            cb: self.dispatch.clone(),\n        }\n    }\n}\n\n/// The base function of [`use_reducer`] and [`use_reducer_eq`]\nfn use_reducer_base<'hook, T>(\n    init_fn: impl 'hook + FnOnce() -> T,\n    should_render_fn: fn(&T, &T) -> bool,\n) -> impl 'hook + Hook<Output = UseReducerHandle<T>>\nwhere\n    T: Reducible + 'static,\n{\n    struct HookProvider<'hook, T, F>\n    where\n        T: Reducible + 'static,\n        F: 'hook + FnOnce() -> T,\n    {\n        _marker: PhantomData<&'hook ()>,\n\n        init_fn: F,\n        should_render_fn: fn(&T, &T) -> bool,\n    }\n\n    impl<'hook, T, F> Hook for HookProvider<'hook, T, F>\n    where\n        T: Reducible + 'static,\n        F: 'hook + FnOnce() -> T,\n    {\n        type Output = UseReducerHandle<T>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let Self {\n                init_fn,\n                should_render_fn,\n                ..\n            } = self;\n\n            let state = ctx.next_state(move |re_render| {\n                let val = Rc::new(RefCell::new(Rc::new(init_fn())));\n                let should_render_fn = Rc::new(should_render_fn);\n\n                UseReducer {\n                    current_state: val.clone(),\n                    dispatch: Rc::new(move |action: T::Action| {\n                        let should_render = {\n                            let should_render_fn = should_render_fn.clone();\n                            let mut val = val.borrow_mut();\n                            let next_val = (*val).clone().reduce(action);\n                            let should_render = should_render_fn(&next_val, &val);\n                            *val = next_val;\n\n                            should_render\n                        };\n\n                        // Currently, this triggers a render immediately, so we need to release the\n                        // borrowed reference first.\n                        if should_render {\n                            re_render()\n                        }\n                    }),\n                }\n            });\n\n            let current_state = state.current_state.clone();\n            let snapshot = state.current_state.borrow().clone();\n            let dispatch = state.dispatch.clone();\n\n            UseReducerHandle {\n                current_state,\n                deref_history: RefCell::new(vec![snapshot]),\n                dispatch,\n            }\n        }\n    }\n\n    HookProvider {\n        _marker: PhantomData,\n        init_fn,\n        should_render_fn,\n    }\n}\n\n/// This hook is an alternative to [`use_state`](super::use_state()).\n/// It is used to handle component's state and is used when complex actions needs to be performed on\n/// said state.\n///\n/// The state is expected to implement the [`Reducible`] trait which provides an `Action` type and a\n/// reducer function.\n///\n/// The state object returned by the initial state function is required to\n/// implement a `Reducible` trait which defines the associated `Action` type and a\n/// reducer function.\n///\n/// This hook will trigger a re-render whenever the reducer function produces a new `Rc` value upon\n/// receiving an action. If the reducer function simply returns the original `Rc` then the component\n/// will not re-render. See [`use_reducer_eq`] if you want the component to first compare the old\n/// and new state and only re-render when the state actually changes.\n///\n/// To cause a re-render even if the reducer function returns the same `Rc`, take a look at\n/// [`use_force_update`].\n///\n/// # Example\n/// ```rust\n/// # use yew::prelude::*;\n/// # use std::rc::Rc;\n/// #\n///\n/// /// reducer's Action\n/// enum CounterAction {\n///     Double,\n///     Square,\n/// }\n///\n/// /// reducer's State\n/// struct CounterState {\n///     counter: i32,\n/// }\n///\n/// impl Default for CounterState {\n///     fn default() -> Self {\n///         Self { counter: 1 }\n///     }\n/// }\n///\n/// impl Reducible for CounterState {\n///     /// Reducer Action Type\n///     type Action = CounterAction;\n///\n///     /// Reducer Function\n///     fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n///         let next_ctr = match action {\n///             CounterAction::Double => self.counter * 2,\n///             CounterAction::Square => self.counter.pow(2),\n///         };\n///\n///         Self { counter: next_ctr }.into()\n///     }\n/// }\n///\n/// #[component(UseReducer)]\n/// fn reducer() -> Html {\n///     // The use_reducer hook takes an initialization function which will be called only once.\n///     let counter = use_reducer(CounterState::default);\n///\n///     let double_onclick = {\n///         let counter = counter.clone();\n///         Callback::from(move |_| counter.dispatch(CounterAction::Double))\n///     };\n///     let square_onclick = {\n///         let counter = counter.clone();\n///         Callback::from(move |_| counter.dispatch(CounterAction::Square))\n///     };\n///\n///     html! {\n///         <>\n///             <div id=\"result\">{ counter.counter }</div>\n///\n///             <button onclick={double_onclick}>{ \"Double\" }</button>\n///             <button onclick={square_onclick}>{ \"Square\" }</button>\n///         </>\n///     }\n/// }\n/// ```\n///\n/// # Tip\n///\n/// The dispatch function is guaranteed to be the same across the entire\n/// component lifecycle. You can safely omit the `UseReducerHandle` from the\n/// dependents of `use_effect_with` if you only intend to dispatch\n/// values from within the hooks.\n///\n/// # Caution\n///\n/// The value held in the handle will reflect the value of at the time the\n/// handle is returned by the `use_reducer`. It is possible that the handle does\n/// not dereference to an up to date value if you are moving it into a\n/// `use_effect_with` hook. You can register the\n/// state to the dependents so the hook can be updated when the value changes.\n#[hook]\npub fn use_reducer<T, F>(init_fn: F) -> UseReducerHandle<T>\nwhere\n    T: Reducible + 'static,\n    F: FnOnce() -> T,\n{\n    use_reducer_base(init_fn, |a, b| !address_eq(a, b))\n}\n\n/// [`use_reducer`] but only re-renders when `prev_state != next_state`.\n///\n/// This requires the state to implement [`PartialEq`] in addition to the [`Reducible`] trait\n/// required by [`use_reducer`].\n#[hook]\npub fn use_reducer_eq<T, F>(init_fn: F) -> UseReducerHandle<T>\nwhere\n    T: Reducible + PartialEq + 'static,\n    F: FnOnce() -> T,\n{\n    use_reducer_base(init_fn, |a, b| !address_eq(a, b) && a != b)\n}\n\n/// Check if two references point to the same address.\nfn address_eq<T>(a: &T, b: &T) -> bool {\n    std::ptr::eq(a as *const T, b as *const T)\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_ref.rs",
    "content": "use std::cell::RefCell;\nuse std::rc::Rc;\n\nuse crate::functional::{hook, use_state, Hook, HookContext};\nuse crate::NodeRef;\n\nstruct UseRef<F> {\n    init_fn: F,\n}\n\nimpl<T: 'static, F: FnOnce() -> T> Hook for UseRef<F> {\n    type Output = Rc<T>;\n\n    fn run(self, ctx: &mut HookContext) -> Self::Output {\n        ctx.next_state(|_| (self.init_fn)())\n    }\n}\n\n/// This hook is used for obtaining a reference to a stateful value.\n/// Its state persists across renders.\n///\n/// Mutation must be done via interior mutability, such as `Cell` or `RefCell`.\n///\n/// It is important to note that you do not get notified of state changes.\n/// If you need the component to be re-rendered on state change, consider using\n/// [`use_state`](super::use_state()).\n///\n/// # Example\n/// ```rust\n/// use std::cell::Cell;\n/// use std::ops::{Deref, DerefMut};\n/// use std::rc::Rc;\n///\n/// use web_sys::HtmlInputElement;\n/// use yew::prelude::*;\n///\n/// #[component(UseRef)]\n/// fn ref_hook() -> Html {\n///     let message = use_state(|| \"\".to_string());\n///     let message_count = use_ref(|| Cell::new(0));\n///\n///     let onclick = Callback::from(move |e| {\n///         let window = gloo::utils::window();\n///\n///         if message_count.get() > 3 {\n///             window.alert_with_message(\"Message limit reached\");\n///         } else {\n///             message_count.set(message_count.get() + 1);\n///             window.alert_with_message(\"Message sent\");\n///         }\n///     });\n///\n///     let onchange = {\n///         let message = message.clone();\n///         Callback::from(move |e: Event| {\n///             let input: HtmlInputElement = e.target_unchecked_into();\n///             message.set(input.value())\n///         })\n///     };\n///\n///     html! {\n///         <div>\n///             <input {onchange} value={(*message).clone()} />\n///             <button {onclick}>{ \"Send\" }</button>\n///         </div>\n///     }\n/// }\npub fn use_ref<T: 'static, F>(init_fn: F) -> impl Hook<Output = Rc<T>>\nwhere\n    F: FnOnce() -> T,\n{\n    UseRef { init_fn }\n}\n\n/// This hook is used for obtaining a mutable reference to a stateful value.\n/// Its state persists across renders.\n///\n/// It is important to note that you do not get notified of state changes.\n/// If you need the component to be re-rendered on state change, consider using\n/// [`use_state`](super::use_state()).\n///\n/// # Example\n/// ```rust\n/// use std::cell::RefCell;\n/// use std::ops::{Deref, DerefMut};\n/// use std::rc::Rc;\n///\n/// use web_sys::HtmlInputElement;\n/// use yew::prelude::*;\n///\n/// #[component(UseRef)]\n/// fn ref_hook() -> Html {\n///     let message = use_state(|| \"\".to_string());\n///     let message_count = use_mut_ref(|| 0);\n///\n///     let onclick = Callback::from(move |e| {\n///         let window = gloo::utils::window();\n///\n///         if *message_count.borrow_mut() > 3 {\n///             window.alert_with_message(\"Message limit reached\");\n///         } else {\n///             *message_count.borrow_mut() += 1;\n///             window.alert_with_message(\"Message sent\");\n///         }\n///     });\n///\n///     let onchange = {\n///         let message = message.clone();\n///         Callback::from(move |e: Event| {\n///             let input: HtmlInputElement = e.target_unchecked_into();\n///             message.set(input.value())\n///         })\n///     };\n///\n///     html! {\n///         <div>\n///             <input {onchange} value={(*message).clone()} />\n///             <button {onclick}>{ \"Send\" }</button>\n///         </div>\n///     }\n/// }\n/// ```\npub fn use_mut_ref<T: 'static, F>(init_fn: F) -> impl Hook<Output = Rc<RefCell<T>>>\nwhere\n    F: FnOnce() -> T,\n{\n    UseRef {\n        init_fn: || RefCell::new(init_fn()),\n    }\n}\n\n/// This hook is used for obtaining a [`NodeRef`].\n/// It persists across renders.\n///\n/// The `ref` attribute can be used to attach the [`NodeRef`] to an HTML element. In callbacks,\n/// you can then get the DOM `Element` that the `ref` is attached to.\n///\n/// # Example\n///\n/// ```rust\n/// use wasm_bindgen::prelude::Closure;\n/// use wasm_bindgen::JsCast;\n/// use web_sys::{Event, HtmlElement};\n/// use yew::{component, html, use_effect_with, use_node_ref, Html};\n///\n/// #[component(UseNodeRef)]\n/// pub fn node_ref_hook() -> Html {\n///     let div_ref = use_node_ref();\n///\n///     {\n///         let div_ref = div_ref.clone();\n///\n///         use_effect_with(div_ref, |div_ref| {\n///             let div = div_ref\n///                 .cast::<HtmlElement>()\n///                 .expect(\"div_ref not attached to div element\");\n///\n///             let listener = Closure::<dyn Fn(Event)>::wrap(Box::new(|_| {\n///                 web_sys::console::log_1(&\"Clicked!\".into());\n///             }));\n///\n///             div.add_event_listener_with_callback(\"click\", listener.as_ref().unchecked_ref())\n///                 .unwrap();\n///\n///             move || {\n///                 div.remove_event_listener_with_callback(\n///                     \"click\",\n///                     listener.as_ref().unchecked_ref(),\n///                 )\n///                 .unwrap();\n///             }\n///         });\n///     }\n///\n///     html! {\n///         <div ref={div_ref}>\n///             { \"Click me and watch the console log!\" }\n///         </div>\n///     }\n/// }\n/// ```\n///\n/// # Tip\n///\n/// When conditionally rendering elements you can use `NodeRef` in conjunction with\n/// `use_effect_with` to perform actions each time an element is rendered and just before the\n/// component where the hook is used in is going to be removed from the DOM.\n#[hook]\npub fn use_node_ref() -> NodeRef {\n    (*use_state(NodeRef::default)).clone()\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_state.rs",
    "content": "use std::fmt;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse implicit_clone::ImplicitClone;\n\nuse super::{use_reducer, use_reducer_eq, Reducible, UseReducerDispatcher, UseReducerHandle};\nuse crate::functional::hook;\nuse crate::html::IntoPropValue;\nuse crate::Callback;\n\nstruct UseStateReducer<T> {\n    value: T,\n}\n\nimpl<T> Reducible for UseStateReducer<T> {\n    type Action = T;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        Rc::new(Self { value: action })\n    }\n}\n\nimpl<T> PartialEq for UseStateReducer<T>\nwhere\n    T: PartialEq,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.value == rhs.value\n    }\n}\n\n/// This hook is used to manage state in a function component.\n///\n/// This hook will always trigger a re-render upon receiving a new state. See [`use_state_eq`]\n/// if you want the component to only re-render when the new state compares unequal\n/// to the existing one.\n///\n/// # Example\n///\n/// ```rust\n/// use yew::prelude::*;\n/// # use std::rc::Rc;\n///\n/// #[component(UseState)]\n/// fn state() -> Html {\n///     let counter = use_state(|| 0);\n///     let onclick = {\n///         let counter = counter.clone();\n///         Callback::from(move |_| counter.set(*counter + 1))\n///     };\n///\n///     html! {\n///         <div>\n///             <button {onclick}>{ \"Increment value\" }</button>\n///             <p>\n///                 <b>{ \"Current value: \" }</b>\n///                 { *counter }\n///             </p>\n///         </div>\n///     }\n/// }\n/// ```\n///\n/// # Caution\n///\n/// The value held in the handle will reflect the value of at the time the\n/// handle is returned by the `use_state()` call. It is possible that the handle does\n/// not dereference to an up to date value, for example if you are moving it into a\n/// `use_effect_with` hook. You can register the\n/// state to the dependents so the hook can be updated when the value changes.\n///\n/// # Tip\n///\n/// The setter function is guaranteed to be the same across the entire\n/// component lifecycle. You can safely omit the `UseStateHandle` from the\n/// dependents of `use_effect_with` if you only intend to set\n/// values from within the hook.\n#[hook]\npub fn use_state<T, F>(init_fn: F) -> UseStateHandle<T>\nwhere\n    T: 'static,\n    F: FnOnce() -> T,\n{\n    let handle = use_reducer(move || UseStateReducer { value: init_fn() });\n\n    UseStateHandle { inner: handle }\n}\n\n/// [`use_state`] but only re-renders when `prev_state != next_state`.\n///\n/// This hook requires the state to implement [`PartialEq`].\n#[hook]\npub fn use_state_eq<T, F>(init_fn: F) -> UseStateHandle<T>\nwhere\n    T: PartialEq + 'static,\n    F: FnOnce() -> T,\n{\n    let handle = use_reducer_eq(move || UseStateReducer { value: init_fn() });\n\n    UseStateHandle { inner: handle }\n}\n\n/// State handle for the [`use_state`] hook.\npub struct UseStateHandle<T> {\n    inner: UseReducerHandle<UseStateReducer<T>>,\n}\n\nimpl<T: fmt::Debug> fmt::Debug for UseStateHandle<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"UseStateHandle\")\n            .field(\"value\", &format!(\"{:?}\", **self))\n            .finish()\n    }\n}\n\nimpl<T> UseStateHandle<T> {\n    /// Replaces the value\n    pub fn set(&self, value: T) {\n        self.inner.dispatch(value)\n    }\n\n    /// Returns the setter of current state.\n    pub fn setter(&self) -> UseStateSetter<T> {\n        UseStateSetter {\n            inner: self.inner.dispatcher(),\n        }\n    }\n}\n\nimpl<T> Deref for UseStateHandle<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner.value\n    }\n}\n\nimpl<T> Clone for UseStateHandle<T> {\n    fn clone(&self) -> Self {\n        Self {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<T> PartialEq for UseStateHandle<T>\nwhere\n    T: PartialEq,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.inner == rhs.inner\n    }\n}\n\nimpl<T> ImplicitClone for UseStateHandle<T> {}\n\n/// Setter handle for [`use_state`] and [`use_state_eq`] hook\npub struct UseStateSetter<T> {\n    inner: UseReducerDispatcher<UseStateReducer<T>>,\n}\n\nimpl<T> Clone for UseStateSetter<T> {\n    fn clone(&self) -> Self {\n        Self {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for UseStateSetter<T>\nwhere\n    T: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"UseStateSetter\").finish()\n    }\n}\n\nimpl<T> From<UseStateSetter<T>> for Callback<T> {\n    fn from(value: UseStateSetter<T>) -> Self {\n        Self::from(value.inner)\n    }\n}\n\nimpl<T> IntoPropValue<Callback<T>> for UseStateSetter<T> {\n    fn into_prop_value(self) -> Callback<T> {\n        self.inner.into_prop_value()\n    }\n}\n\nimpl<T> PartialEq for UseStateSetter<T> {\n    fn eq(&self, rhs: &Self) -> bool {\n        self.inner == rhs.inner\n    }\n}\n\nimpl<T> ImplicitClone for UseStateSetter<T> {}\n\nimpl<T> UseStateSetter<T> {\n    /// Replaces the value\n    pub fn set(&self, value: T) {\n        self.inner.dispatch(value)\n    }\n\n    /// Get a callback, invoking which is equivalent to calling `set()`\n    /// on this same setter.\n    pub fn to_callback(&self) -> Callback<T> {\n        self.inner.to_callback()\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_transitive_state/feat_hydration.rs",
    "content": "//! The hydration variant.\n//!\n//! This is the same as the use_prepared_state.\n\n#[doc(hidden)]\npub use crate::functional::hooks::use_prepared_state::feat_hydration::use_prepared_state as use_transitive_state;\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_transitive_state/feat_hydration_ssr.rs",
    "content": "//! The client-and-server-side rendering variant.\n\nuse std::rc::Rc;\n\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\n\nuse super::{feat_hydration, feat_ssr};\nuse crate::functional::{Hook, HookContext};\nuse crate::html::RenderMode;\nuse crate::suspense::SuspensionResult;\n\n#[doc(hidden)]\npub fn use_transitive_state<T, D, F>(\n    deps: D,\n    f: F,\n) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: 'static + FnOnce(Rc<D>) -> T,\n{\n    struct HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: 'static + FnOnce(Rc<D>) -> T,\n    {\n        deps: D,\n        f: F,\n    }\n\n    impl<T, D, F> Hook for HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: 'static + FnOnce(Rc<D>) -> T,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            match ctx.creation_mode {\n                RenderMode::Ssr => feat_ssr::use_transitive_state(self.deps, self.f).run(ctx),\n                _ => feat_hydration::use_transitive_state(self.deps).run(ctx),\n            }\n        }\n    }\n\n    HookProvider::<T, D, F> { deps, f }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_transitive_state/feat_none.rs",
    "content": "//! The noop variant. This is used for client side rendering when hydration is disabled.\n\n#[doc(hidden)]\npub use crate::functional::hooks::use_prepared_state::feat_none::use_prepared_state as use_transitive_state;\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_transitive_state/feat_ssr.rs",
    "content": "//! The server-side rendering variant.\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse base64ct::{Base64, Encoding};\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\n\nuse crate::functional::{Hook, HookContext, PreparedState};\nuse crate::suspense::SuspensionResult;\n\npub(super) struct TransitiveStateBase<T, D, F>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: 'static + FnOnce(Rc<D>) -> T,\n{\n    pub state_fn: RefCell<Option<F>>,\n    pub deps: Rc<D>,\n}\n\nimpl<T, D, F> PreparedState for TransitiveStateBase<T, D, F>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: 'static + FnOnce(Rc<D>) -> T,\n{\n    fn prepare(&self) -> String {\n        let f = self.state_fn.borrow_mut().take().unwrap();\n        let state = f(self.deps.clone());\n\n        let state = bincode::serde::encode_to_vec(\n            (Some(&state), Some(&*self.deps)),\n            bincode::config::standard(),\n        )\n        .expect(\"failed to prepare state\");\n\n        Base64::encode_string(&state)\n    }\n}\n\n#[doc(hidden)]\npub fn use_transitive_state<T, D, F>(\n    deps: D,\n    f: F,\n) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>\nwhere\n    D: Serialize + DeserializeOwned + PartialEq + 'static,\n    T: Serialize + DeserializeOwned + 'static,\n    F: 'static + FnOnce(Rc<D>) -> T,\n{\n    struct HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: 'static + FnOnce(Rc<D>) -> T,\n    {\n        deps: D,\n        f: F,\n    }\n\n    impl<T, D, F> Hook for HookProvider<T, D, F>\n    where\n        D: Serialize + DeserializeOwned + PartialEq + 'static,\n        T: Serialize + DeserializeOwned + 'static,\n        F: 'static + FnOnce(Rc<D>) -> T,\n    {\n        type Output = SuspensionResult<Option<Rc<T>>>;\n\n        fn run(self, ctx: &mut HookContext) -> Self::Output {\n            let f = self.f;\n\n            ctx.next_prepared_state(move |_re_render, _| -> TransitiveStateBase<T, D, F> {\n                TransitiveStateBase {\n                    state_fn: Some(f).into(),\n                    deps: self.deps.into(),\n                }\n            });\n\n            Ok(None)\n        }\n    }\n\n    HookProvider::<T, D, F> { deps, f }\n}\n"
  },
  {
    "path": "packages/yew/src/functional/hooks/use_transitive_state/mod.rs",
    "content": "#[cfg(feature = \"hydration\")]\nmod feat_hydration;\n#[cfg(all(feature = \"ssr\", feature = \"hydration\"))]\nmod feat_hydration_ssr;\n#[cfg(not(any(feature = \"hydration\", feature = \"ssr\")))]\nmod feat_none;\n#[cfg(feature = \"ssr\")]\nmod feat_ssr;\n\n#[cfg(all(feature = \"hydration\", not(feature = \"ssr\")))]\npub use feat_hydration::*;\n#[cfg(all(feature = \"ssr\", feature = \"hydration\"))]\npub use feat_hydration_ssr::*;\n#[cfg(not(any(feature = \"hydration\", feature = \"ssr\")))]\npub use feat_none::*;\n#[cfg(all(feature = \"ssr\", not(feature = \"hydration\")))]\npub use feat_ssr::*;\n/// Use a state created as an artifact of the server-side rendering.\n///\n/// This value is created after the server-side rendering artifact is created.\n///\n/// It accepts a closure as the first argument and a dependency type as the second argument.\n/// It returns `SuspensionResult<Option<Rc<T>>>`.\n///\n/// It will always return `Ok(None)` during server-side rendering.\n///\n/// During hydration, it will only return `Ok(Some(Rc<T>))` if the component is hydrated from a\n/// server-side rendering artifact and its dependency value matches.\n///\n/// `let state = use_transitive_state!(deps, |deps| -> ReturnType { ... });`\n///\n/// It has the following function signature:\n///\n/// ```\n/// # use serde::de::DeserializeOwned;\n/// # use serde::Serialize;\n/// # use std::rc::Rc;\n/// use yew::prelude::*;\n/// use yew::suspense::SuspensionResult;\n///\n/// #[hook]\n/// pub fn use_transitive_state<T, D, F>(deps: D, f: F) -> SuspensionResult<Option<Rc<T>>>\n/// where\n///     D: Serialize + DeserializeOwned + PartialEq + 'static,\n///     T: Serialize + DeserializeOwned + 'static,\n///     F: 'static + FnOnce(Rc<D>) -> T,\n/// # { todo!() }\n/// ```\n///\n/// If the bundle is compiled without server-side rendering, the closure will be stripped\n/// automatically.\n///\n/// # Note\n///\n/// You MUST denote the return type of the closure with `|deps| -> ReturnType { ... }`. This\n/// type is used during client side rendering to deserialize the state prepared on the server\n/// side.\npub use use_transitive_state_macro as use_transitive_state;\n// With SSR.\n#[doc(hidden)]\n#[cfg(feature = \"ssr\")]\npub use yew_macro::use_transitive_state_with_closure as use_transitive_state_macro;\n// Without SSR.\n#[doc(hidden)]\n#[cfg(not(feature = \"ssr\"))]\npub use yew_macro::use_transitive_state_without_closure as use_transitive_state_macro;\n"
  },
  {
    "path": "packages/yew/src/functional/mod.rs",
    "content": "//! Function components are a simplified version of normal components.\n//! They consist of a single function annotated with the attribute `#[component]`\n//! that receives props and determines what should be rendered by returning [`Html`](crate::Html).\n//!\n//! Functions with the attribute have to return `Html` and may take a single parameter for the type\n//! of props the component should accept. The parameter type needs to be a reference to a\n//! `Properties` type (ex. `props: &MyProps`). If the function doesn't have any parameters the\n//! resulting component doesn't accept any props.\n//!\n//! Just mark the component with the attribute. The component will be named after the function.\n//!\n//! ```rust\n//! # use yew::prelude::*;\n//! #\n//! #[component]\n//! fn HelloWorld() -> Html {\n//!     html! { \"Hello world\" }\n//! }\n//! ```\n//!\n//! More details about function components and Hooks can be found on [Yew Docs](https://yew.rs/docs/next/concepts/function-components/introduction)\n\nuse std::any::Any;\nuse std::cell::RefCell;\nuse std::fmt;\nuse std::rc::Rc;\n\nuse wasm_bindgen::prelude::*;\n\n#[cfg(all(feature = \"hydration\", feature = \"ssr\"))]\nuse crate::html::RenderMode;\nuse crate::html::{AnyScope, BaseComponent, Context, HtmlResult};\nuse crate::Properties;\n\nmod hooks;\npub use hooks::*;\n/// This attribute creates a function component from a normal Rust function.\n///\n/// Functions with this attribute **must** return `Html` and can optionally take an argument\n/// for props. Note that the function only receives a reference to the props.\n///\n/// When using this attribute you need to provide a name for the component:\n/// `#component(ComponentName)]`.\n/// The attribute will then automatically create a [`FunctionComponent`] with the given\n/// identifier which you can use like a normal component.\n///\n/// # Example\n/// ```rust\n/// # use yew::prelude::*;\n/// #\n/// # #[derive(Properties, Clone, PartialEq)]\n/// # pub struct Props {\n/// #     text: String\n/// # }\n/// #\n/// #[component(NameOfComponent)]\n/// pub fn component(props: &Props) -> Html {\n///     html! {\n///         <p>{ &props.text }</p>\n///     }\n/// }\n/// ```\npub use yew_macro::function_component as component;\n/// A re-export of [`component`](yew_macro::function_component) with the older name.\n#[deprecated(since = \"0.22.0\", note = \"renamed to `#[component]\")]\npub use yew_macro::function_component;\n/// This attribute creates a user-defined hook from a normal Rust function.\npub use yew_macro::hook;\n\ntype ReRender = Rc<dyn Fn()>;\n\n/// Primitives of a prepared state hook.\n#[cfg(any(feature = \"hydration\", feature = \"ssr\"))]\npub(crate) trait PreparedState {\n    #[cfg(feature = \"ssr\")]\n    fn prepare(&self) -> String;\n}\n\n/// Primitives of an effect hook.\npub(crate) trait Effect {\n    fn rendered(&self) {}\n}\n\n/// A hook context to be passed to hooks.\npub struct HookContext {\n    pub(crate) scope: AnyScope,\n    #[cfg(all(feature = \"hydration\", feature = \"ssr\"))]\n    creation_mode: RenderMode,\n    re_render: ReRender,\n\n    states: Vec<Rc<dyn Any>>,\n    effects: Vec<Rc<dyn Effect>>,\n\n    #[cfg(any(feature = \"hydration\", feature = \"ssr\"))]\n    prepared_states: Vec<Rc<dyn PreparedState>>,\n\n    #[cfg(feature = \"hydration\")]\n    prepared_states_data: Vec<Rc<str>>,\n    #[cfg(feature = \"hydration\")]\n    prepared_state_counter: usize,\n\n    counter: usize,\n    #[cfg(debug_assertions)]\n    total_hook_counter: Option<usize>,\n}\n\nimpl HookContext {\n    fn new(\n        scope: AnyScope,\n        re_render: ReRender,\n        #[cfg(all(feature = \"hydration\", feature = \"ssr\"))] creation_mode: RenderMode,\n        #[cfg(feature = \"hydration\")] prepared_state: Option<&str>,\n    ) -> RefCell<Self> {\n        RefCell::new(HookContext {\n            scope,\n            re_render,\n\n            #[cfg(all(feature = \"hydration\", feature = \"ssr\"))]\n            creation_mode,\n\n            states: Vec::new(),\n\n            #[cfg(any(feature = \"hydration\", feature = \"ssr\"))]\n            prepared_states: Vec::new(),\n            effects: Vec::new(),\n\n            #[cfg(feature = \"hydration\")]\n            prepared_states_data: {\n                match prepared_state {\n                    Some(m) => m.split(',').map(Rc::from).collect(),\n                    None => Vec::new(),\n                }\n            },\n            #[cfg(feature = \"hydration\")]\n            prepared_state_counter: 0,\n\n            counter: 0,\n            #[cfg(debug_assertions)]\n            total_hook_counter: None,\n        })\n    }\n\n    pub(crate) fn next_state<T>(&mut self, initializer: impl FnOnce(ReRender) -> T) -> Rc<T>\n    where\n        T: 'static,\n    {\n        // Determine which hook position we're at and increment for the next hook\n        let hook_pos = self.counter;\n        self.counter += 1;\n\n        let state = match self.states.get(hook_pos).cloned() {\n            Some(m) => m,\n            None => {\n                let initial_state = Rc::new(initializer(self.re_render.clone()));\n                self.states.push(initial_state.clone());\n\n                initial_state\n            }\n        };\n\n        state.downcast().unwrap_throw()\n    }\n\n    pub(crate) fn next_effect<T>(&mut self, initializer: impl FnOnce(ReRender) -> T) -> Rc<T>\n    where\n        T: 'static + Effect,\n    {\n        let prev_state_len = self.states.len();\n        let t = self.next_state(initializer);\n\n        // This is a new effect, we add it to effects.\n        if self.states.len() != prev_state_len {\n            self.effects.push(t.clone());\n        }\n\n        t\n    }\n\n    #[cfg(any(feature = \"hydration\", feature = \"ssr\"))]\n    pub(crate) fn next_prepared_state<T>(\n        &mut self,\n        initializer: impl FnOnce(ReRender, Option<&str>) -> T,\n    ) -> Rc<T>\n    where\n        T: 'static + PreparedState,\n    {\n        #[cfg(not(feature = \"hydration\"))]\n        let prepared_state = Option::<Rc<str>>::None;\n\n        #[cfg(feature = \"hydration\")]\n        let prepared_state = {\n            let prepared_state_pos = self.prepared_state_counter;\n            self.prepared_state_counter += 1;\n\n            self.prepared_states_data.get(prepared_state_pos).cloned()\n        };\n\n        let prev_state_len = self.states.len();\n        let t = self.next_state(move |re_render| initializer(re_render, prepared_state.as_deref()));\n\n        // This is a new effect, we add it to effects.\n        if self.states.len() != prev_state_len {\n            self.prepared_states.push(t.clone());\n        }\n\n        t\n    }\n\n    #[inline(always)]\n    fn prepare_run(&mut self) {\n        #[cfg(feature = \"hydration\")]\n        {\n            self.prepared_state_counter = 0;\n        }\n\n        self.counter = 0;\n    }\n\n    /// asserts hook counter.\n    ///\n    /// This function asserts that the number of hooks matches for every render.\n    #[cfg(debug_assertions)]\n    fn assert_hook_context(&mut self, render_ok: bool) {\n        // Procedural Macros can catch most conditionally called hooks at compile time, but it\n        // cannot detect early return (as the return can be Err(_), Suspension).\n        match (render_ok, self.total_hook_counter) {\n            // First rendered,\n            // we store the hook counter.\n            (true, None) => {\n                self.total_hook_counter = Some(self.counter);\n            }\n            // Component is suspended before it's first rendered.\n            // We don't have a total count to compare with.\n            (false, None) => {}\n\n            // Subsequent render,\n            // we compare stored total count and current render count.\n            (true, Some(total_hook_counter)) => assert_eq!(\n                total_hook_counter, self.counter,\n                \"Hooks are called conditionally.\"\n            ),\n\n            // Subsequent suspension,\n            // components can have less hooks called when suspended, but not more.\n            (false, Some(total_hook_counter)) => assert!(\n                self.counter <= total_hook_counter,\n                \"Hooks are called conditionally.\"\n            ),\n        }\n    }\n\n    fn run_effects(&self) {\n        for effect in self.effects.iter() {\n            effect.rendered();\n        }\n    }\n\n    fn drain_states(&mut self) {\n        // We clear the effects as these are also references to states.\n        self.effects.clear();\n\n        for state in self.states.drain(..) {\n            drop(state);\n        }\n    }\n\n    #[cfg(not(feature = \"ssr\"))]\n    fn prepare_state(&self) -> Option<String> {\n        None\n    }\n\n    #[cfg(feature = \"ssr\")]\n    fn prepare_state(&self) -> Option<String> {\n        if self.prepared_states.is_empty() {\n            return None;\n        }\n\n        let prepared_states = self.prepared_states.clone();\n\n        let mut states = Vec::new();\n\n        for state in prepared_states.iter() {\n            let state = state.prepare();\n            states.push(state);\n        }\n\n        Some(states.join(\",\"))\n    }\n}\n\nimpl fmt::Debug for HookContext {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"HookContext<_>\")\n    }\n}\n\n/// Trait that allows a struct to act as Function Component.\npub trait FunctionProvider {\n    /// Properties for the Function Component.\n    type Properties: Properties + PartialEq;\n\n    /// Render the component. This function returns the [`Html`](crate::Html) to be rendered for the\n    /// component.\n    ///\n    /// Equivalent of [`Component::view`](crate::html::Component::view).\n    fn run(ctx: &mut HookContext, props: &Self::Properties) -> HtmlResult;\n}\n\n/// A type that interacts [`FunctionProvider`] to provide lifecycle events to be bridged to\n/// [`BaseComponent`].\n///\n/// # Note\n///\n/// Function Components should not be implemented with this type directly.\n///\n/// Use the `#[component]` macro instead.\n#[doc(hidden)]\npub struct FunctionComponent<T>\nwhere\n    T: FunctionProvider,\n{\n    _never: std::marker::PhantomData<T>,\n    hook_ctx: RefCell<HookContext>,\n}\n\nimpl<T> FunctionComponent<T>\nwhere\n    T: FunctionProvider + 'static,\n{\n    /// Creates a new function component.\n    pub fn new(ctx: &Context<T>) -> Self\n    where\n        T: BaseComponent<Message = ()> + FunctionProvider + 'static,\n    {\n        let scope = AnyScope::from(ctx.link().clone());\n        let re_render = {\n            let link = ctx.link().clone();\n\n            Rc::new(move || link.send_message(()))\n        };\n\n        Self {\n            _never: std::marker::PhantomData,\n            hook_ctx: HookContext::new(\n                scope,\n                re_render,\n                #[cfg(all(feature = \"hydration\", feature = \"ssr\"))]\n                ctx.creation_mode(),\n                #[cfg(feature = \"hydration\")]\n                ctx.prepared_state(),\n            ),\n        }\n    }\n\n    /// Renders a function component.\n    pub fn render(&self, props: &T::Properties) -> HtmlResult {\n        let mut hook_ctx = self.hook_ctx.borrow_mut();\n\n        hook_ctx.prepare_run();\n\n        #[allow(clippy::let_and_return)]\n        let result = T::run(&mut hook_ctx, props);\n\n        #[cfg(debug_assertions)]\n        hook_ctx.assert_hook_context(result.is_ok());\n\n        result\n    }\n\n    /// Run Effects of a function component.\n    pub fn rendered(&self) {\n        let hook_ctx = self.hook_ctx.borrow();\n        hook_ctx.run_effects();\n    }\n\n    /// Destroys the function component.\n    pub fn destroy(&self) {\n        let mut hook_ctx = self.hook_ctx.borrow_mut();\n        hook_ctx.drain_states();\n    }\n\n    /// Prepares the server-side state.\n    pub fn prepare_state(&self) -> Option<String> {\n        let hook_ctx = self.hook_ctx.borrow();\n        hook_ctx.prepare_state()\n    }\n}\n\nimpl<T> fmt::Debug for FunctionComponent<T>\nwhere\n    T: FunctionProvider + 'static,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"FunctionComponent<_>\")\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/classes.rs",
    "content": "use std::borrow::Cow;\nuse std::iter::FromIterator;\nuse std::rc::Rc;\n\nuse indexmap::IndexSet;\n\nuse super::IntoPropValue;\nuse crate::html::ImplicitClone;\nuse crate::utils::RcExt;\nuse crate::virtual_dom::AttrValue;\n\n/// A set of classes, cheap to clone.\n///\n/// The preferred way of creating this is using the [`classes!`][yew::classes!] macro.\n#[derive(Debug, Clone, ImplicitClone, Default)]\npub struct Classes {\n    set: Rc<IndexSet<AttrValue>>,\n}\n\n/// helper method to efficiently turn a set of classes into a space-separated\n/// string. Abstracts differences between ToString and IntoPropValue. The\n/// `rest` iterator is cloned to pre-compute the length of the String; it\n/// should be cheap to clone.\nfn build_attr_value(first: AttrValue, rest: impl Iterator<Item = AttrValue> + Clone) -> AttrValue {\n    // The length of the string is known to be the length of all the\n    // components, plus one space for each element in `rest`.\n    let mut s = String::with_capacity(\n        rest.clone()\n            .map(|class| class.len())\n            .chain([first.len(), rest.size_hint().0])\n            .sum(),\n    );\n\n    s.push_str(first.as_str());\n    // NOTE: this can be improved once Iterator::intersperse() becomes stable\n    for class in rest {\n        s.push(' ');\n        s.push_str(class.as_str());\n    }\n    s.into()\n}\n\nimpl Classes {\n    /// Creates an empty set of classes. (Does not allocate.)\n    #[inline]\n    pub fn new() -> Self {\n        Self {\n            set: Rc::new(IndexSet::new()),\n        }\n    }\n\n    /// Creates an empty set of classes with capacity for n elements. (Does not allocate if n is\n    /// zero.)\n    #[inline]\n    pub fn with_capacity(n: usize) -> Self {\n        Self {\n            set: Rc::new(IndexSet::with_capacity(n)),\n        }\n    }\n\n    /// Adds a class to a set.\n    ///\n    /// If the provided class has already been added, this method will ignore it.\n    pub fn push<T: Into<Self>>(&mut self, class: T) {\n        let classes_to_add: Self = class.into();\n        if self.is_empty() {\n            *self = classes_to_add\n        } else {\n            Rc::make_mut(&mut self.set).extend(classes_to_add.set.iter().cloned())\n        }\n    }\n\n    /// Adds a class to a set.\n    ///\n    /// If the provided class has already been added, this method will ignore it.\n    ///\n    /// This method won't check if there are multiple classes in the input string.\n    ///\n    /// # Safety\n    ///\n    /// This function will not split the string into multiple classes. Please do not use it unless\n    /// you are absolutely certain that the string does not contain any whitespace and it is not\n    /// empty. Using `push()`  is preferred.\n    pub unsafe fn unchecked_push<T: Into<AttrValue>>(&mut self, class: T) {\n        Rc::make_mut(&mut self.set).insert(class.into());\n    }\n\n    /// Check the set contains a class.\n    #[inline]\n    pub fn contains<T: AsRef<str>>(&self, class: T) -> bool {\n        self.set.contains(class.as_ref())\n    }\n\n    /// Check the set is empty.\n    #[inline]\n    pub fn is_empty(&self) -> bool {\n        self.set.is_empty()\n    }\n}\n\nimpl IntoPropValue<AttrValue> for Classes {\n    #[inline]\n    fn into_prop_value(self) -> AttrValue {\n        let mut classes = self.set.iter().cloned();\n\n        match classes.next() {\n            None => AttrValue::Static(\"\"),\n            Some(class) if classes.len() == 0 => class,\n            Some(first) => build_attr_value(first, classes),\n        }\n    }\n}\n\nimpl IntoPropValue<Option<AttrValue>> for Classes {\n    #[inline]\n    fn into_prop_value(self) -> Option<AttrValue> {\n        if self.is_empty() {\n            None\n        } else {\n            Some(self.into_prop_value())\n        }\n    }\n}\n\nimpl IntoPropValue<Classes> for &'static str {\n    #[inline]\n    fn into_prop_value(self) -> Classes {\n        self.into()\n    }\n}\n\nimpl<T: Into<Classes>> Extend<T> for Classes {\n    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {\n        iter.into_iter().for_each(|classes| self.push(classes))\n    }\n}\n\nimpl<T: Into<Classes>> FromIterator<T> for Classes {\n    fn from_iter<IT: IntoIterator<Item = T>>(iter: IT) -> Self {\n        let mut classes = Self::new();\n        classes.extend(iter);\n        classes\n    }\n}\n\nimpl IntoIterator for Classes {\n    type IntoIter = indexmap::set::IntoIter<AttrValue>;\n    type Item = AttrValue;\n\n    #[inline]\n    fn into_iter(self) -> Self::IntoIter {\n        RcExt::unwrap_or_clone(self.set).into_iter()\n    }\n}\n\nimpl IntoIterator for &Classes {\n    type IntoIter = indexmap::set::IntoIter<AttrValue>;\n    type Item = AttrValue;\n\n    #[inline]\n    fn into_iter(self) -> Self::IntoIter {\n        (*self.set).clone().into_iter()\n    }\n}\n\n#[allow(clippy::to_string_trait_impl)]\nimpl ToString for Classes {\n    fn to_string(&self) -> String {\n        let mut iter = self.set.iter().cloned();\n\n        iter.next()\n            .map(|first| build_attr_value(first, iter))\n            .unwrap_or_default()\n            .to_string()\n    }\n}\n\nimpl From<Cow<'static, str>> for Classes {\n    fn from(t: Cow<'static, str>) -> Self {\n        match t {\n            Cow::Borrowed(x) => Self::from(x),\n            Cow::Owned(x) => Self::from(x),\n        }\n    }\n}\n\nimpl From<&'static str> for Classes {\n    fn from(t: &'static str) -> Self {\n        let set = t.split_whitespace().map(AttrValue::Static).collect();\n        Self { set: Rc::new(set) }\n    }\n}\n\nimpl From<String> for Classes {\n    fn from(t: String) -> Self {\n        match t.contains(|c: char| c.is_whitespace()) {\n            // If the string only contains a single class, we can just use it\n            // directly (rather than cloning it into a new string). Need to make\n            // sure it's not empty, though.\n            false => match t.is_empty() {\n                true => Self::new(),\n                false => Self {\n                    set: Rc::new(IndexSet::from_iter([AttrValue::from(t)])),\n                },\n            },\n            true => Self::from(&t),\n        }\n    }\n}\n\nimpl From<&String> for Classes {\n    fn from(t: &String) -> Self {\n        let set = t\n            .split_whitespace()\n            .map(ToOwned::to_owned)\n            .map(AttrValue::from)\n            .collect();\n        Self { set: Rc::new(set) }\n    }\n}\n\nimpl From<&AttrValue> for Classes {\n    fn from(t: &AttrValue) -> Self {\n        let set = t\n            .split_whitespace()\n            .map(ToOwned::to_owned)\n            .map(AttrValue::from)\n            .collect();\n        Self { set: Rc::new(set) }\n    }\n}\n\nimpl From<AttrValue> for Classes {\n    fn from(t: AttrValue) -> Self {\n        match t.contains(|c: char| c.is_whitespace()) {\n            // If the string only contains a single class, we can just use it\n            // directly (rather than cloning it into a new string). Need to make\n            // sure it's not empty, though.\n            false => match t.is_empty() {\n                true => Self::new(),\n                false => Self {\n                    set: Rc::new(IndexSet::from_iter([t])),\n                },\n            },\n            true => Self::from(&t),\n        }\n    }\n}\n\nimpl<T: Into<Classes>> From<Option<T>> for Classes {\n    fn from(t: Option<T>) -> Self {\n        t.map(|x| x.into()).unwrap_or_default()\n    }\n}\n\nimpl<T: Into<Classes> + Clone> From<&Option<T>> for Classes {\n    fn from(t: &Option<T>) -> Self {\n        Self::from(t.clone())\n    }\n}\n\nimpl<T: Into<Classes>> From<Vec<T>> for Classes {\n    fn from(t: Vec<T>) -> Self {\n        Self::from_iter(t)\n    }\n}\n\nimpl<T: Into<Classes> + Clone> From<&[T]> for Classes {\n    fn from(t: &[T]) -> Self {\n        t.iter().cloned().collect()\n    }\n}\n\nimpl<T: Into<Classes>, const SIZE: usize> From<[T; SIZE]> for Classes {\n    fn from(t: [T; SIZE]) -> Self {\n        t.into_iter().collect()\n    }\n}\n\nimpl From<&Classes> for Classes {\n    fn from(c: &Classes) -> Self {\n        c.clone()\n    }\n}\n\nimpl From<&Classes> for AttrValue {\n    fn from(c: &Classes) -> Self {\n        c.clone().into_prop_value()\n    }\n}\n\nimpl PartialEq for Classes {\n    fn eq(&self, other: &Self) -> bool {\n        self.set.len() == other.set.len() && self.set.iter().eq(other.set.iter())\n    }\n}\n\nimpl Eq for Classes {}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    struct TestClass;\n\n    impl TestClass {\n        fn as_class(&self) -> &'static str {\n            \"test-class\"\n        }\n    }\n\n    impl From<TestClass> for Classes {\n        fn from(x: TestClass) -> Self {\n            Classes::from(x.as_class())\n        }\n    }\n\n    #[test]\n    fn it_is_initially_empty() {\n        let subject = Classes::new();\n        assert!(subject.is_empty());\n    }\n\n    #[test]\n    fn it_pushes_value() {\n        let mut subject = Classes::new();\n        subject.push(\"foo\");\n        assert!(!subject.is_empty());\n        assert!(subject.contains(\"foo\"));\n    }\n\n    #[test]\n    fn it_adds_values_via_extend() {\n        let mut other = Classes::new();\n        other.push(\"bar\");\n        let mut subject = Classes::new();\n        subject.extend(other);\n        assert!(subject.contains(\"bar\"));\n    }\n\n    #[test]\n    fn it_contains_both_values() {\n        let mut other = Classes::new();\n        other.push(\"bar\");\n        let mut subject = Classes::new();\n        subject.extend(other);\n        subject.push(\"foo\");\n        assert!(subject.contains(\"foo\"));\n        assert!(subject.contains(\"bar\"));\n    }\n\n    #[test]\n    fn it_splits_class_with_spaces() {\n        let mut subject = Classes::new();\n        subject.push(\"foo bar\");\n        assert!(subject.contains(\"foo\"));\n        assert!(subject.contains(\"bar\"));\n    }\n\n    #[test]\n    fn push_and_contains_can_be_used_with_other_objects() {\n        let mut subject = Classes::new();\n        subject.push(TestClass);\n        let other_class: Option<TestClass> = None;\n        subject.push(other_class);\n        assert!(subject.contains(TestClass.as_class()));\n    }\n\n    #[test]\n    fn can_be_extended_with_another_class() {\n        let mut other = Classes::new();\n        other.push(\"foo\");\n        other.push(\"bar\");\n        let mut subject = Classes::new();\n        subject.extend(&other);\n        subject.extend(other);\n        assert!(subject.contains(\"foo\"));\n        assert!(subject.contains(\"bar\"));\n    }\n\n    #[test]\n    fn can_be_collected() {\n        let classes = vec![\"foo\", \"bar\"];\n        let subject = classes.into_iter().collect::<Classes>();\n        assert!(subject.contains(\"foo\"));\n        assert!(subject.contains(\"bar\"));\n    }\n\n    #[test]\n    fn ignores_empty_string() {\n        let classes = String::from(\"\");\n        let subject = Classes::from(classes);\n        assert!(subject.is_empty())\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/component/children.rs",
    "content": "//! Component children module\n\nuse std::fmt;\nuse std::rc::Rc;\n\nuse crate::html::{Html, ImplicitClone};\nuse crate::utils::RcExt;\nuse crate::virtual_dom::{VChild, VComp, VList, VNode};\nuse crate::{BaseComponent, Properties};\n\n/// A type used for accepting children elements in Component::Properties.\n///\n/// # Example\n/// **`model.rs`**\n///\n/// In this example, the `Wrapper` component is used to wrap other elements.\n/// ```\n/// # use yew::{Children, Html, Properties, Component, Context, html};\n/// # #[derive(Clone, Properties, PartialEq)]\n/// # struct WrapperProps {\n/// #     children: Children,\n/// # }\n/// # struct Wrapper;\n/// # impl Component for Wrapper {\n/// #     type Message = ();\n/// #     type Properties = WrapperProps;\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html {\n/// html! {\n///     <Wrapper>\n///         <h4>{ \"Hi\" }</h4>\n///         <div>{ \"Hello\" }</div>\n///     </Wrapper>\n/// }\n/// #     }\n/// # }\n/// ```\n///\n/// **`wrapper.rs`**\n///\n/// The Wrapper component must define a `children` property in order to wrap other elements. The\n/// children property can be used to render the wrapped elements.\n/// ```\n/// # use yew::{Children, Html, Properties, Component, Context, html};\n/// #[derive(Clone, Properties, PartialEq)]\n/// struct WrapperProps {\n///     children: Children,\n/// }\n///\n/// # struct Wrapper;\n/// impl Component for Wrapper {\n///     // ...\n/// #     type Message = ();\n/// #     type Properties = WrapperProps;\n/// #    fn create(ctx: &Context<Self>) -> Self { Self }\n///     fn view(&self, ctx: &Context<Self>) -> Html {\n///         html! {\n///             <div id=\"container\">\n///                 { ctx.props().children.clone() }\n///             </div>\n///         }\n///     }\n/// }\n/// ```\npub type Children = ChildrenRenderer<Html>;\n\n/// A type used for accepting children elements in Component::Properties and accessing their props.\n///\n/// # Example\n/// **`model.rs`**\n///\n/// In this example, the `List` component can wrap `ListItem` components.\n/// ```\n/// # use yew::{html, Component, Html, Context, ChildrenWithProps, Properties};\n/// #\n/// # #[derive(Clone, Properties, PartialEq)]\n/// # struct ListProps {\n/// #     children: ChildrenWithProps<ListItem>,\n/// # }\n/// # struct List;\n/// # impl Component for List {\n/// #     type Message = ();\n/// #     type Properties = ListProps;\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html { unimplemented!() }\n/// # }\n/// # #[derive(Clone, Properties, PartialEq)]\n/// # struct ListItemProps {\n/// #     value: String\n/// # }\n/// # struct ListItem;\n/// # impl Component for ListItem {\n/// #     type Message = ();\n/// #     type Properties = ListItemProps;\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html { unimplemented!() }\n/// # }\n/// # fn view() -> Html {\n/// html! {\n///   <List>\n///     <ListItem value=\"a\" />\n///     <ListItem value=\"b\" />\n///     <ListItem value=\"c\" />\n///   </List>\n/// }\n/// # }\n/// ```\n///\n/// **`list.rs`**\n///\n/// The `List` component must define a `children` property in order to wrap the list items. The\n/// `children` property can be used to filter, mutate, and render the items.\n/// ```\n/// # use yew::{html, Component, Html, ChildrenWithProps, Context, Properties};\n/// # use std::rc::Rc;\n/// #\n/// #[derive(Clone, Properties, PartialEq)]\n/// struct ListProps {\n///     children: ChildrenWithProps<ListItem>,\n/// }\n///\n/// # struct List;\n/// impl Component for List {\n/// #     type Message = ();\n/// #     type Properties = ListProps;\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html {\n///         html!{{\n///             for ctx.props().children.iter().map(|mut item| {\n///                 let mut props = Rc::make_mut(&mut item.props);\n///                 props.value = format!(\"item-{}\", props.value);\n///                 item\n///             })\n///         }}\n///     }\n/// }\n/// #\n/// # #[derive(Clone, Properties, PartialEq)]\n/// # struct ListItemProps {\n/// #     #[prop_or_default]\n/// #     value: String\n/// # }\n/// #\n/// # struct ListItem;\n/// # impl Component for ListItem {\n/// #     type Message = ();\n/// #     type Properties = ListItemProps;\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html { unimplemented!() }\n/// # }\n/// ```\npub type ChildrenWithProps<CHILD> = ChildrenRenderer<VChild<CHILD>>;\n\n/// A type used for rendering children html.\npub struct ChildrenRenderer<T> {\n    pub(crate) children: Option<Rc<Vec<T>>>,\n}\n\nimpl<T> Clone for ChildrenRenderer<T> {\n    fn clone(&self) -> Self {\n        Self {\n            children: self.children.clone(),\n        }\n    }\n}\n\nimpl<T> ImplicitClone for ChildrenRenderer<T> {}\n\nimpl<T: PartialEq> PartialEq for ChildrenRenderer<T> {\n    fn eq(&self, other: &Self) -> bool {\n        match (self.children.as_ref(), other.children.as_ref()) {\n            (Some(a), Some(b)) => a == b,\n            (Some(a), None) => a.is_empty(),\n            (None, Some(b)) => b.is_empty(),\n            (None, None) => true,\n        }\n    }\n}\n\nimpl<T> ChildrenRenderer<T>\nwhere\n    T: Clone,\n{\n    /// Create children\n    pub fn new(children: Vec<T>) -> Self {\n        if children.is_empty() {\n            Self { children: None }\n        } else {\n            Self {\n                children: Some(Rc::new(children)),\n            }\n        }\n    }\n\n    /// Children list is empty\n    pub fn is_empty(&self) -> bool {\n        self.children.as_ref().map(|x| x.is_empty()).unwrap_or(true)\n    }\n\n    /// Number of children elements\n    pub fn len(&self) -> usize {\n        self.children.as_ref().map(|x| x.len()).unwrap_or(0)\n    }\n\n    /// Render children components and return `Iterator`\n    pub fn iter(&self) -> impl Iterator<Item = T> + '_ {\n        // clone each child lazily.\n        // This way `self.iter().next()` only has to clone a single node.\n        self.children.iter().flat_map(|x| x.iter()).cloned()\n    }\n\n    /// Convert the children elements to another object (if there are any).\n    ///\n    /// ```\n    /// # let children = Children::new(Vec::new());\n    /// # use yew::{classes, html, Children};\n    /// # let _ =\n    /// children.map(|children| {\n    ///     html! {\n    ///         <div class={classes!(\"container\")}>\n    ///             {children}\n    ///         </div>\n    ///     }\n    /// })\n    /// # ;\n    /// ```\n    pub fn map<OUT: Default>(&self, closure: impl FnOnce(&Self) -> OUT) -> OUT {\n        if self.is_empty() {\n            Default::default()\n        } else {\n            closure(self)\n        }\n    }\n}\n\nimpl<T> Default for ChildrenRenderer<T> {\n    fn default() -> Self {\n        Self {\n            children: Default::default(),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for ChildrenRenderer<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"ChildrenRenderer<_>\")\n    }\n}\n\nimpl<T: Clone> IntoIterator for ChildrenRenderer<T> {\n    type IntoIter = std::vec::IntoIter<Self::Item>;\n    type Item = T;\n\n    fn into_iter(self) -> Self::IntoIter {\n        if let Some(children) = self.children {\n            let children = RcExt::unwrap_or_clone(children);\n            children.into_iter()\n        } else {\n            Vec::new().into_iter()\n        }\n    }\n}\n\nimpl From<ChildrenRenderer<Html>> for Html {\n    fn from(mut val: ChildrenRenderer<Html>) -> Self {\n        if let Some(children) = val.children.as_mut() {\n            if children.len() == 1 {\n                let children = Rc::make_mut(children);\n                if let Some(m) = children.pop() {\n                    return m;\n                }\n            }\n        }\n\n        Html::VList(Rc::new(val.into()))\n    }\n}\n\nimpl From<ChildrenRenderer<Html>> for VList {\n    fn from(val: ChildrenRenderer<Html>) -> Self {\n        VList::from(val.children)\n    }\n}\n\nimpl<COMP> From<ChildrenRenderer<VChild<COMP>>> for ChildrenRenderer<Html>\nwhere\n    COMP: BaseComponent,\n{\n    fn from(value: ChildrenRenderer<VChild<COMP>>) -> Self {\n        Self::new(\n            value\n                .into_iter()\n                .map(VComp::from)\n                .map(VNode::from)\n                .collect::<Vec<_>>(),\n        )\n    }\n}\n\n/// A [Properties] type with Children being the only property.\n#[derive(Debug, Properties, PartialEq)]\npub struct ChildrenProps {\n    /// The Children of a Component.\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn children_map() {\n        let children = Children::new(vec![]);\n        let res = children.map(|children| Some(children.clone()));\n        assert!(res.is_none());\n        let children = Children::new(vec![Default::default()]);\n        let res = children.map(|children| Some(children.clone()));\n        assert!(res.is_some());\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/component/lifecycle.rs",
    "content": "//! Component lifecycle module\n\nuse std::any::Any;\nuse std::rc::Rc;\n\n#[cfg(feature = \"csr\")]\nuse web_sys::Element;\n\nuse super::scope::{AnyScope, Scope};\nuse super::BaseComponent;\n#[cfg(feature = \"hydration\")]\nuse crate::dom_bundle::Fragment;\n#[cfg(feature = \"csr\")]\nuse crate::dom_bundle::{BSubtree, Bundle, DomSlot, DynamicDomSlot};\n#[cfg(feature = \"hydration\")]\nuse crate::html::RenderMode;\nuse crate::html::{Html, RenderError};\nuse crate::scheduler::{self, Runnable, Shared};\nuse crate::suspense::{BaseSuspense, Suspension};\nuse crate::{Callback, Context, HtmlResult};\n\npub(crate) enum ComponentRenderState {\n    #[cfg(feature = \"csr\")]\n    Render {\n        bundle: Bundle,\n        root: BSubtree,\n        parent: Element,\n        /// The dom position in front of the next sibling.\n        /// Gets updated when the bundle in which this component occurs gets re-rendered and is\n        /// shared with the children of this component.\n        sibling_slot: DynamicDomSlot,\n        /// The dom position in front of this component.\n        /// Gets updated whenever this component re-renders and is shared with the bundle in which\n        /// this component occurs.\n        own_slot: DynamicDomSlot,\n    },\n    #[cfg(feature = \"hydration\")]\n    Hydration {\n        fragment: Fragment,\n        root: BSubtree,\n        parent: Element,\n        sibling_slot: DynamicDomSlot,\n        own_slot: DynamicDomSlot,\n    },\n    #[cfg(feature = \"ssr\")]\n    Ssr {\n        sender: Option<crate::platform::pinned::oneshot::Sender<Html>>,\n    },\n}\n\nimpl std::fmt::Debug for ComponentRenderState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            #[cfg(feature = \"csr\")]\n            Self::Render {\n                ref bundle,\n                root,\n                ref parent,\n                ref sibling_slot,\n                ref own_slot,\n            } => f\n                .debug_struct(\"ComponentRenderState::Render\")\n                .field(\"bundle\", bundle)\n                .field(\"root\", root)\n                .field(\"parent\", parent)\n                .field(\"sibling_slot\", sibling_slot)\n                .field(\"own_slot\", own_slot)\n                .finish(),\n\n            #[cfg(feature = \"hydration\")]\n            Self::Hydration {\n                ref fragment,\n                ref parent,\n                ref sibling_slot,\n                ref own_slot,\n                ref root,\n            } => f\n                .debug_struct(\"ComponentRenderState::Hydration\")\n                .field(\"fragment\", fragment)\n                .field(\"root\", root)\n                .field(\"parent\", parent)\n                .field(\"sibling_slot\", sibling_slot)\n                .field(\"own_slot\", own_slot)\n                .finish(),\n\n            #[cfg(feature = \"ssr\")]\n            Self::Ssr { ref sender } => {\n                let sender_repr = match sender {\n                    Some(_) => \"Some(_)\",\n                    None => \"None\",\n                };\n\n                f.debug_struct(\"ComponentRenderState::Ssr\")\n                    .field(\"sender\", &sender_repr)\n                    .finish()\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"csr\")]\nimpl ComponentRenderState {\n    pub(crate) fn shift(&mut self, next_parent: Element, next_slot: DomSlot) {\n        match self {\n            #[cfg(feature = \"csr\")]\n            Self::Render {\n                bundle,\n                parent,\n                sibling_slot,\n                ..\n            } => {\n                *parent = next_parent;\n                sibling_slot.reassign(next_slot);\n                bundle.shift(parent, sibling_slot.to_position());\n            }\n            #[cfg(feature = \"hydration\")]\n            Self::Hydration {\n                fragment,\n                parent,\n                sibling_slot,\n                ..\n            } => {\n                *parent = next_parent;\n                sibling_slot.reassign(next_slot);\n                fragment.shift(parent, sibling_slot.to_position());\n            }\n\n            #[cfg(feature = \"ssr\")]\n            Self::Ssr { .. } => {\n                #[cfg(debug_assertions)]\n                panic!(\"shifting is not possible during SSR\");\n            }\n        }\n    }\n}\n\nstruct CompStateInner<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    pub(crate) component: COMP,\n    pub(crate) context: Context<COMP>,\n}\n\n/// A trait to provide common,\n/// generic free behaviour across all components to reduce code size.\n///\n/// Mostly a thin wrapper that passes the context to a component's lifecycle\n/// methods.\npub(crate) trait Stateful {\n    fn view(&self) -> HtmlResult;\n    #[cfg(feature = \"csr\")]\n    fn rendered(&mut self, first_render: bool);\n    fn destroy(&mut self);\n\n    fn any_scope(&self) -> AnyScope;\n\n    fn flush_messages(&mut self) -> bool;\n    #[cfg(feature = \"csr\")]\n    fn props_changed(&mut self, props: Rc<dyn Any>) -> bool;\n\n    fn as_any(&self) -> &dyn Any;\n\n    #[cfg(feature = \"hydration\")]\n    fn creation_mode(&self) -> RenderMode;\n}\n\nimpl<COMP> Stateful for CompStateInner<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    fn view(&self) -> HtmlResult {\n        self.component.view(&self.context)\n    }\n\n    #[cfg(feature = \"csr\")]\n    fn rendered(&mut self, first_render: bool) {\n        self.component.rendered(&self.context, first_render)\n    }\n\n    fn destroy(&mut self) {\n        self.component.destroy(&self.context);\n    }\n\n    fn any_scope(&self) -> AnyScope {\n        self.context.link().clone().into()\n    }\n\n    #[cfg(feature = \"hydration\")]\n    fn creation_mode(&self) -> RenderMode {\n        self.context.creation_mode()\n    }\n\n    fn flush_messages(&mut self) -> bool {\n        let mut changed = false;\n        for msg in self.context.link().pending_messages.drain() {\n            if self.component.update(&self.context, msg) {\n                changed = true;\n            }\n        }\n        changed\n    }\n\n    #[cfg(feature = \"csr\")]\n    fn props_changed(&mut self, props: Rc<dyn Any>) -> bool {\n        let props = match Rc::downcast::<COMP::Properties>(props) {\n            Ok(m) => m,\n            _ => return false,\n        };\n\n        if self.context.props != props {\n            let old_props = std::mem::replace(&mut self.context.props, props);\n            self.component.changed(&self.context, &old_props)\n        } else {\n            false\n        }\n    }\n\n    fn as_any(&self) -> &dyn Any {\n        self\n    }\n}\n\npub(crate) struct ComponentState {\n    pub(super) inner: Box<dyn Stateful>,\n\n    pub(super) render_state: ComponentRenderState,\n\n    #[cfg(feature = \"csr\")]\n    has_rendered: bool,\n    /// This deals with an edge case. Usually, we want to update props as fast as possible.\n    /// But, when a component hydrates and suspends, we want to continue using the initially given\n    /// props. This is prop updates are ignored during SSR, too.\n    #[cfg(feature = \"hydration\")]\n    pending_props: Option<Rc<dyn Any>>,\n\n    suspension: Option<Suspension>,\n\n    pub(crate) comp_id: usize,\n}\n\nimpl ComponentState {\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        name = \"create\",\n        skip_all,\n        fields(component.id = scope.id),\n    )]\n    fn new<COMP: BaseComponent>(\n        initial_render_state: ComponentRenderState,\n        scope: Scope<COMP>,\n        props: Rc<COMP::Properties>,\n        #[cfg(feature = \"hydration\")] prepared_state: Option<String>,\n    ) -> Self {\n        let comp_id = scope.id;\n        #[cfg(feature = \"hydration\")]\n        let creation_mode = {\n            match initial_render_state {\n                ComponentRenderState::Render { .. } => RenderMode::Render,\n                ComponentRenderState::Hydration { .. } => RenderMode::Hydration,\n                #[cfg(feature = \"ssr\")]\n                ComponentRenderState::Ssr { .. } => RenderMode::Ssr,\n            }\n        };\n\n        let context = Context {\n            scope,\n            props,\n            #[cfg(feature = \"hydration\")]\n            creation_mode,\n            #[cfg(feature = \"hydration\")]\n            prepared_state,\n        };\n\n        let inner = Box::new(CompStateInner {\n            component: COMP::create(&context),\n            context,\n        });\n\n        Self {\n            inner,\n            render_state: initial_render_state,\n            suspension: None,\n\n            #[cfg(feature = \"csr\")]\n            has_rendered: false,\n            #[cfg(feature = \"hydration\")]\n            pending_props: None,\n\n            comp_id,\n        }\n    }\n\n    pub(crate) fn downcast_comp_ref<COMP>(&self) -> Option<&COMP>\n    where\n        COMP: BaseComponent + 'static,\n    {\n        self.inner\n            .as_any()\n            .downcast_ref::<CompStateInner<COMP>>()\n            .map(|m| &m.component)\n    }\n\n    fn resume_existing_suspension(&mut self) {\n        if let Some(m) = self.suspension.take() {\n            let comp_scope = self.inner.any_scope();\n\n            let suspense_scope = comp_scope.find_parent_scope::<BaseSuspense>().unwrap();\n            BaseSuspense::resume(&suspense_scope, m);\n        }\n    }\n}\n\npub(crate) struct CreateRunner<COMP: BaseComponent> {\n    pub initial_render_state: ComponentRenderState,\n    pub props: Rc<COMP::Properties>,\n    pub scope: Scope<COMP>,\n    #[cfg(feature = \"hydration\")]\n    pub prepared_state: Option<String>,\n}\n\nimpl<COMP: BaseComponent> Runnable for CreateRunner<COMP> {\n    fn run(self: Box<Self>) {\n        let mut current_state = self.scope.state.borrow_mut();\n        if current_state.is_none() {\n            *current_state = Some(ComponentState::new(\n                self.initial_render_state,\n                self.scope.clone(),\n                self.props,\n                #[cfg(feature = \"hydration\")]\n                self.prepared_state,\n            ));\n        }\n    }\n}\n\npub(crate) struct UpdateRunner {\n    pub state: Shared<Option<ComponentState>>,\n}\n\nimpl ComponentState {\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        skip(self),\n        fields(component.id = self.comp_id)\n    )]\n    fn update(&mut self) -> bool {\n        let schedule_render = self.inner.flush_messages();\n        tracing::trace!(schedule_render);\n        schedule_render\n    }\n}\n\nimpl Runnable for UpdateRunner {\n    fn run(self: Box<Self>) {\n        if let Some(state) = self.state.borrow_mut().as_mut() {\n            let schedule_render = state.update();\n\n            if schedule_render {\n                scheduler::push_component_render(\n                    state.comp_id,\n                    Box::new(RenderRunner {\n                        state: self.state.clone(),\n                    }),\n                );\n                // Only run from the scheduler, so no need to call `scheduler::start()`\n            }\n        }\n    }\n}\n\npub(crate) struct DestroyRunner {\n    pub state: Shared<Option<ComponentState>>,\n    pub parent_to_detach: bool,\n}\n\nimpl ComponentState {\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        skip(self),\n        fields(component.id = self.comp_id)\n    )]\n    fn destroy(mut self, parent_to_detach: bool) {\n        self.inner.destroy();\n        self.resume_existing_suspension();\n\n        match self.render_state {\n            #[cfg(feature = \"csr\")]\n            ComponentRenderState::Render {\n                bundle,\n                ref parent,\n                ref root,\n                ..\n            } => {\n                bundle.detach(root, parent, parent_to_detach);\n            }\n            // We need to detach the hydrate fragment if the component is not hydrated.\n            #[cfg(feature = \"hydration\")]\n            ComponentRenderState::Hydration {\n                ref root,\n                fragment,\n                ref parent,\n                ..\n            } => {\n                fragment.detach(root, parent, parent_to_detach);\n            }\n\n            #[cfg(feature = \"ssr\")]\n            ComponentRenderState::Ssr { .. } => {\n                let _ = parent_to_detach;\n            }\n        }\n    }\n}\n\nimpl Runnable for DestroyRunner {\n    fn run(self: Box<Self>) {\n        if let Some(state) = self.state.borrow_mut().take() {\n            state.destroy(self.parent_to_detach);\n        }\n    }\n}\n\npub(crate) struct RenderRunner {\n    pub state: Shared<Option<ComponentState>>,\n}\n\nimpl ComponentState {\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        skip_all,\n        fields(component.id = self.comp_id)\n    )]\n    fn render(&mut self, shared_state: &Shared<Option<ComponentState>>) {\n        let view = self.inner.view();\n        tracing::trace!(?view, \"render result\");\n        match view {\n            Ok(vnode) => self.commit_render(shared_state, vnode),\n            Err(RenderError::Suspended(susp)) => self.suspend(shared_state, susp),\n        };\n    }\n\n    fn suspend(&mut self, shared_state: &Shared<Option<ComponentState>>, suspension: Suspension) {\n        // Currently suspended, we re-use previous root node and send\n        // suspension to parent element.\n\n        if suspension.resumed() {\n            // schedule a render immediately if suspension is resumed.\n            scheduler::push_component_render(\n                self.comp_id,\n                Box::new(RenderRunner {\n                    state: shared_state.clone(),\n                }),\n            );\n        } else {\n            // We schedule a render after current suspension is resumed.\n            let comp_scope = self.inner.any_scope();\n\n            let suspense_scope = comp_scope\n                .find_parent_scope::<BaseSuspense>()\n                .expect(\"To suspend rendering, a <Suspense /> component is required.\");\n\n            let comp_id = self.comp_id;\n            let shared_state = shared_state.clone();\n            suspension.listen(Callback::from(move |_| {\n                scheduler::push_component_render(\n                    comp_id,\n                    Box::new(RenderRunner {\n                        state: shared_state.clone(),\n                    }),\n                );\n                scheduler::start();\n            }));\n\n            if let Some(ref last_suspension) = self.suspension {\n                if &suspension != last_suspension {\n                    // We remove previous suspension from the suspense.\n                    BaseSuspense::resume(&suspense_scope, last_suspension.clone());\n                }\n            }\n            self.suspension = Some(suspension.clone());\n\n            BaseSuspense::suspend(&suspense_scope, suspension);\n        }\n    }\n\n    fn commit_render(&mut self, shared_state: &Shared<Option<ComponentState>>, new_vdom: Html) {\n        // Currently not suspended, we remove any previous suspension and update\n        // normally.\n        self.resume_existing_suspension();\n\n        match self.render_state {\n            #[cfg(feature = \"csr\")]\n            ComponentRenderState::Render {\n                ref mut bundle,\n                ref parent,\n                ref root,\n                ref sibling_slot,\n                ref mut own_slot,\n                ..\n            } => {\n                let scope = self.inner.any_scope();\n\n                let new_node_ref =\n                    bundle.reconcile(root, &scope, parent, sibling_slot.to_position(), new_vdom);\n                own_slot.reassign(new_node_ref);\n\n                let first_render = !self.has_rendered;\n                self.has_rendered = true;\n\n                scheduler::push_component_rendered(\n                    self.comp_id,\n                    Box::new(RenderedRunner {\n                        state: shared_state.clone(),\n                        first_render,\n                    }),\n                    first_render,\n                );\n            }\n\n            #[cfg(feature = \"hydration\")]\n            ComponentRenderState::Hydration {\n                ref mut fragment,\n                ref parent,\n                ref mut own_slot,\n                ref mut sibling_slot,\n                ref root,\n            } => {\n                // We schedule a \"first\" render to run immediately after hydration.\n                // Most notably, only this render will trigger the \"rendered\" callback, hence we\n                // want to prioritize this.\n                scheduler::push_component_priority_render(\n                    self.comp_id,\n                    Box::new(RenderRunner {\n                        state: shared_state.clone(),\n                    }),\n                );\n\n                let scope = self.inner.any_scope();\n                let bundle = Bundle::hydrate(\n                    root,\n                    &scope,\n                    parent,\n                    fragment,\n                    new_vdom,\n                    &mut Some(own_slot.clone()),\n                );\n\n                // We trim all text nodes before checking as it's likely these are whitespaces.\n                fragment.trim_start_text_nodes();\n                assert!(fragment.is_empty(), \"expected end of component, found node\");\n\n                self.render_state = ComponentRenderState::Render {\n                    root: root.clone(),\n                    bundle,\n                    parent: parent.clone(),\n                    own_slot: own_slot.take(),\n                    sibling_slot: sibling_slot.take(),\n                };\n            }\n\n            #[cfg(feature = \"ssr\")]\n            ComponentRenderState::Ssr { ref mut sender } => {\n                let _ = shared_state;\n                if let Some(tx) = sender.take() {\n                    tx.send(new_vdom).unwrap();\n                }\n            }\n        };\n    }\n}\n\nimpl Runnable for RenderRunner {\n    fn run(self: Box<Self>) {\n        let mut state = self.state.borrow_mut();\n        let state = match state.as_mut() {\n            None => return, // skip for components that have already been destroyed\n            Some(state) => state,\n        };\n\n        state.render(&self.state);\n    }\n}\n\n#[cfg(feature = \"csr\")]\nmod feat_csr {\n    use super::*;\n\n    pub(crate) struct PropsUpdateRunner {\n        pub state: Shared<Option<ComponentState>>,\n        pub props: Option<Rc<dyn Any>>,\n        pub next_sibling_slot: Option<DomSlot>,\n    }\n\n    impl ComponentState {\n        #[tracing::instrument(\n            level = tracing::Level::DEBUG,\n            skip(self),\n            fields(component.id = self.comp_id)\n        )]\n        fn changed(\n            &mut self,\n            props: Option<Rc<dyn Any>>,\n            next_sibling_slot: Option<DomSlot>,\n        ) -> bool {\n            if let Some(next_sibling_slot) = next_sibling_slot {\n                // When components are updated, their siblings were likely also updated\n                // We also need to shift the bundle so next sibling will be synced to child\n                // components.\n                match &mut self.render_state {\n                    #[cfg(feature = \"csr\")]\n                    ComponentRenderState::Render { sibling_slot, .. } => {\n                        sibling_slot.reassign(next_sibling_slot);\n                    }\n\n                    #[cfg(feature = \"hydration\")]\n                    ComponentRenderState::Hydration { sibling_slot, .. } => {\n                        sibling_slot.reassign(next_sibling_slot);\n                    }\n\n                    #[cfg(feature = \"ssr\")]\n                    ComponentRenderState::Ssr { .. } => {\n                        #[cfg(debug_assertions)]\n                        panic!(\"properties do not change during SSR\");\n                    }\n                }\n            }\n\n            let should_render = |props: Option<Rc<dyn Any>>, state: &mut ComponentState| -> bool {\n                props.map(|m| state.inner.props_changed(m)).unwrap_or(false)\n            };\n\n            #[cfg(feature = \"hydration\")]\n            let should_render_hydration =\n                |props: Option<Rc<dyn Any>>, state: &mut ComponentState| -> bool {\n                    if let Some(props) = props.or_else(|| state.pending_props.take()) {\n                        match state.has_rendered {\n                            true => {\n                                state.pending_props = None;\n                                state.inner.props_changed(props)\n                            }\n                            false => {\n                                state.pending_props = Some(props);\n                                false\n                            }\n                        }\n                    } else {\n                        false\n                    }\n                };\n\n            // Only trigger changed if props were changed / next sibling has changed.\n            let schedule_render = {\n                #[cfg(feature = \"hydration\")]\n                {\n                    if self.inner.creation_mode() == RenderMode::Hydration {\n                        should_render_hydration(props, self)\n                    } else {\n                        should_render(props, self)\n                    }\n                }\n\n                #[cfg(not(feature = \"hydration\"))]\n                should_render(props, self)\n            };\n\n            tracing::trace!(\n                \"props_update(has_rendered={} schedule_render={})\",\n                self.has_rendered,\n                schedule_render\n            );\n            schedule_render\n        }\n    }\n\n    impl Runnable for PropsUpdateRunner {\n        fn run(self: Box<Self>) {\n            let Self {\n                next_sibling_slot,\n                props,\n                state: shared_state,\n            } = *self;\n\n            if let Some(state) = shared_state.borrow_mut().as_mut() {\n                let schedule_render = state.changed(props, next_sibling_slot);\n\n                if schedule_render {\n                    scheduler::push_component_render(\n                        state.comp_id,\n                        Box::new(RenderRunner {\n                            state: shared_state.clone(),\n                        }),\n                    );\n                    // Only run from the scheduler, so no need to call `scheduler::start()`\n                }\n            };\n        }\n    }\n\n    pub(crate) struct RenderedRunner {\n        pub state: Shared<Option<ComponentState>>,\n        pub first_render: bool,\n    }\n\n    impl ComponentState {\n        #[tracing::instrument(\n            level = tracing::Level::DEBUG,\n            skip(self),\n            fields(component.id = self.comp_id)\n        )]\n        fn rendered(&mut self, first_render: bool) -> bool {\n            if self.suspension.is_none() {\n                self.inner.rendered(first_render);\n            }\n\n            #[cfg(feature = \"hydration\")]\n            {\n                self.pending_props.is_some()\n            }\n            #[cfg(not(feature = \"hydration\"))]\n            {\n                false\n            }\n        }\n    }\n\n    impl Runnable for RenderedRunner {\n        fn run(self: Box<Self>) {\n            if let Some(state) = self.state.borrow_mut().as_mut() {\n                let has_pending_props = state.rendered(self.first_render);\n\n                if has_pending_props {\n                    scheduler::push_component_props_update(Box::new(PropsUpdateRunner {\n                        state: self.state.clone(),\n                        props: None,\n                        next_sibling_slot: None,\n                    }));\n                }\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"csr\")]\npub(super) use feat_csr::*;\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod tests {\n    extern crate self as yew;\n\n    use std::cell::RefCell;\n    use std::ops::Deref;\n    use std::rc::Rc;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use super::*;\n    use crate::dom_bundle::BSubtree;\n    use crate::html::*;\n    use crate::{html, Properties};\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[derive(Clone, Properties, Default, PartialEq)]\n    struct ChildProps {\n        lifecycle: Rc<RefCell<Vec<String>>>,\n    }\n\n    struct Child {}\n\n    impl Component for Child {\n        type Message = ();\n        type Properties = ChildProps;\n\n        fn create(_ctx: &Context<Self>) -> Self {\n            Child {}\n        }\n\n        fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n            ctx.props()\n                .lifecycle\n                .borrow_mut()\n                .push(\"child rendered\".into());\n        }\n\n        fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n            false\n        }\n\n        fn changed(&mut self, _ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n            false\n        }\n\n        fn view(&self, _ctx: &Context<Self>) -> Html {\n            html! {}\n        }\n    }\n\n    #[derive(Clone, Properties, Default, PartialEq)]\n    struct Props {\n        lifecycle: Rc<RefCell<Vec<String>>>,\n        #[allow(dead_code)]\n        #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n        create_message: Option<bool>,\n        update_message: RefCell<Option<bool>>,\n        view_message: RefCell<Option<bool>>,\n        rendered_message: RefCell<Option<bool>>,\n    }\n\n    struct Comp {\n        lifecycle: Rc<RefCell<Vec<String>>>,\n    }\n\n    impl Component for Comp {\n        type Message = bool;\n        type Properties = Props;\n\n        fn create(ctx: &Context<Self>) -> Self {\n            ctx.props().lifecycle.borrow_mut().push(\"create\".into());\n            #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n            if let Some(msg) = ctx.props().create_message {\n                ctx.link().send_message(msg);\n            }\n            Comp {\n                lifecycle: Rc::clone(&ctx.props().lifecycle),\n            }\n        }\n\n        fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {\n            if let Some(msg) = ctx.props().rendered_message.borrow_mut().take() {\n                ctx.link().send_message(msg);\n            }\n            ctx.props()\n                .lifecycle\n                .borrow_mut()\n                .push(format!(\"rendered({})\", first_render));\n        }\n\n        fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n            if let Some(msg) = ctx.props().update_message.borrow_mut().take() {\n                ctx.link().send_message(msg);\n            }\n            ctx.props()\n                .lifecycle\n                .borrow_mut()\n                .push(format!(\"update({})\", msg));\n            msg\n        }\n\n        fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n            self.lifecycle = Rc::clone(&ctx.props().lifecycle);\n            self.lifecycle.borrow_mut().push(\"change\".into());\n            false\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> Html {\n            if let Some(msg) = ctx.props().view_message.borrow_mut().take() {\n                ctx.link().send_message(msg);\n            }\n            self.lifecycle.borrow_mut().push(\"view\".into());\n            html! { <Child lifecycle={self.lifecycle.clone()} /> }\n        }\n    }\n\n    impl Drop for Comp {\n        fn drop(&mut self) {\n            self.lifecycle.borrow_mut().push(\"drop\".into());\n        }\n    }\n\n    fn test_lifecycle(props: Props, expected: &[&str]) {\n        let document = gloo::utils::document();\n        let scope = Scope::<Comp>::new(None);\n        let parent = document.create_element(\"div\").unwrap();\n        let root = BSubtree::create_root(&parent);\n\n        let lifecycle = props.lifecycle.clone();\n\n        lifecycle.borrow_mut().clear();\n        let _ = scope.mount_in_place(root, parent, DomSlot::at_end(), Rc::new(props));\n        crate::scheduler::start_now();\n\n        assert_eq!(&lifecycle.borrow_mut().deref()[..], expected);\n    }\n\n    #[test]\n    fn lifecycle_tests() {\n        let lifecycle: Rc<RefCell<Vec<String>>> = Rc::default();\n\n        test_lifecycle(\n            Props {\n                lifecycle: lifecycle.clone(),\n                ..Props::default()\n            },\n            &[\"create\", \"view\", \"child rendered\", \"rendered(true)\"],\n        );\n\n        test_lifecycle(\n            Props {\n                lifecycle: lifecycle.clone(),\n                #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n                create_message: Some(false),\n                ..Props::default()\n            },\n            &[\n                \"create\",\n                \"view\",\n                \"child rendered\",\n                \"rendered(true)\",\n                \"update(false)\",\n            ],\n        );\n\n        test_lifecycle(\n            Props {\n                lifecycle: lifecycle.clone(),\n                view_message: RefCell::new(Some(true)),\n                ..Props::default()\n            },\n            &[\n                \"create\",\n                \"view\",\n                \"child rendered\",\n                \"rendered(true)\",\n                \"update(true)\",\n                \"view\",\n                \"rendered(false)\",\n            ],\n        );\n\n        test_lifecycle(\n            Props {\n                lifecycle: lifecycle.clone(),\n                view_message: RefCell::new(Some(false)),\n                ..Props::default()\n            },\n            &[\n                \"create\",\n                \"view\",\n                \"child rendered\",\n                \"rendered(true)\",\n                \"update(false)\",\n            ],\n        );\n\n        test_lifecycle(\n            Props {\n                lifecycle: lifecycle.clone(),\n                rendered_message: RefCell::new(Some(false)),\n                ..Props::default()\n            },\n            &[\n                \"create\",\n                \"view\",\n                \"child rendered\",\n                \"rendered(true)\",\n                \"update(false)\",\n            ],\n        );\n\n        test_lifecycle(\n            Props {\n                lifecycle: lifecycle.clone(),\n                rendered_message: RefCell::new(Some(true)),\n                ..Props::default()\n            },\n            &[\n                \"create\",\n                \"view\",\n                \"child rendered\",\n                \"rendered(true)\",\n                \"update(true)\",\n                \"view\",\n                \"rendered(false)\",\n            ],\n        );\n\n        // This also tests render deduplication after the first render\n        test_lifecycle(\n            Props {\n                lifecycle,\n                #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n                create_message: Some(true),\n                update_message: RefCell::new(Some(true)),\n                ..Props::default()\n            },\n            &[\n                \"create\",\n                \"view\",\n                \"child rendered\",\n                \"rendered(true)\",\n                \"update(true)\",\n                \"update(true)\",\n                \"view\",\n                \"rendered(false)\",\n            ],\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/component/marker.rs",
    "content": "//! Primitive Components & Properties Types\n\nuse crate::component;\nuse crate::html::{BaseComponent, ChildrenProps, Html};\n\n/// A Component to represent a component that does not exist in current implementation.\n///\n/// During Hydration, Yew expected the Virtual DOM hierarchy to match the layout used in\n/// server-side rendering. However, sometimes it is possible / reasonable to omit certain components\n/// from one side of the implementation. This component is used to represent a component as if a\n/// component \"existed\" in the place it is defined.\n///\n/// # Warning\n///\n/// The Real DOM hierarchy must also match the server-side rendered artifact. This component is\n/// only usable when the original component does not introduce any additional elements. (e.g.:\n/// Context Providers)\n///\n/// A generic parameter is provided to help identify the component to be substituted.\n/// The type of the generic parameter is not required to be the same component that was in the other\n/// implementation. However, this behaviour may change in the future if more debug assertions were\n/// to be introduced. It is recommended that the generic parameter represents the component in the\n/// other implementation.\n///\n/// # Example\n///\n/// ```\n/// use yew::prelude::*;\n/// # use yew::html::ChildrenProps;\n/// #\n/// # #[component]\n/// # fn Comp(props: &ChildrenProps) -> Html {\n/// #     Html::default()\n/// # }\n/// #\n/// # #[component]\n/// # fn Provider(props: &ChildrenProps) -> Html {\n/// #     let children = props.children.clone();\n/// #\n/// #     html! { <>{children}</> }\n/// # }\n/// # type Provider1 = Provider;\n/// # type Provider2 = Provider;\n/// # type Provider3 = Provider;\n/// # type Provider4 = Provider;\n///\n/// #[component]\n/// fn ServerApp() -> Html {\n///     // The Server Side Rendering Application has 3 Providers.\n///     html! {\n///         <Provider1>\n///             <Provider2>\n///                 <Provider3>\n///                     <Comp />\n///                 </Provider3>\n///             </Provider2>\n///         </Provider1>\n///     }\n/// }\n///\n/// #[component]\n/// fn App() -> Html {\n///     // The Client Side Rendering Application has 4 Providers.\n///     html! {\n///         <Provider1>\n///             <Provider2>\n///                 <Provider3>\n///\n///                     // This provider does not exist on the server-side\n///                     // Hydration will fail due to Virtual DOM layout mismatch.\n///                     <Provider4>\n///                         <Comp />\n///                     </Provider4>\n///\n///                 </Provider3>\n///             </Provider2>\n///         </Provider1>\n///     }\n/// }\n/// ```\n///\n/// To mitigate this, we can use a `PhantomComponent`:\n///\n/// ```\n/// use yew::prelude::*;\n/// # use yew::html::{PhantomComponent, ChildrenProps};\n/// #\n/// # #[component]\n/// # fn Comp(props: &ChildrenProps) -> Html {\n/// #     Html::default()\n/// # }\n/// #\n/// # #[component]\n/// # fn Provider(props: &ChildrenProps) -> Html {\n/// #     let children = props.children.clone();\n/// #\n/// #     html! { <>{children}</> }\n/// # }\n/// # type Provider1 = Provider;\n/// # type Provider2 = Provider;\n/// # type Provider3 = Provider;\n/// # type Provider4 = Provider;\n///\n/// #[component]\n/// fn ServerApp() -> Html {\n///     html! {\n///         <Provider1>\n///             <Provider2>\n///                 <Provider3>\n///                     // We add a PhantomComponent for Provider4,\n///                     // it acts if a Provider4 component presents in this position.\n///                     <PhantomComponent<Provider4>>\n///                         <Comp />\n///                     </PhantomComponent<Provider4>>\n///                 </Provider3>\n///             </Provider2>\n///         </Provider1>\n///     }\n/// }\n///\n/// #[component]\n/// fn App() -> Html {\n///     html! {\n///         <Provider1>\n///             <Provider2>\n///                 <Provider3>\n///\n///                     // Hydration will succeed as the PhantomComponent in the server-side\n///                     // implementation will represent a Provider4 component in this position.\n///                     <Provider4>\n///                         <Comp />\n///                     </Provider4>\n///\n///                 </Provider3>\n///             </Provider2>\n///         </Provider1>\n///     }\n/// }\n/// ```\n#[component]\npub fn PhantomComponent<T>(props: &ChildrenProps) -> Html\nwhere\n    T: BaseComponent,\n{\n    props.children.clone()\n}\n"
  },
  {
    "path": "packages/yew/src/html/component/mod.rs",
    "content": "//! Components wrapped with context including properties, state, and link\n\nmod children;\n#[cfg(any(feature = \"csr\", feature = \"ssr\"))]\nmod lifecycle;\nmod marker;\nmod properties;\nmod scope;\n\nuse std::rc::Rc;\n\npub use children::*;\npub use marker::*;\npub use properties::*;\n#[cfg(feature = \"csr\")]\npub(crate) use scope::Scoped;\npub use scope::{AnyScope, Scope, SendAsMessage};\n\nuse super::{Html, HtmlResult, IntoHtmlResult};\n\n#[cfg(feature = \"hydration\")]\n#[derive(Debug, Clone, Copy, PartialEq)]\npub(crate) enum RenderMode {\n    Hydration,\n    Render,\n    #[cfg(feature = \"ssr\")]\n    Ssr,\n}\n\n/// The [`Component`]'s context. This contains component's [`Scope`] and props and\n/// is passed to every lifecycle method.\n#[derive(Debug)]\npub struct Context<COMP: BaseComponent> {\n    scope: Scope<COMP>,\n    props: Rc<COMP::Properties>,\n    #[cfg(feature = \"hydration\")]\n    creation_mode: RenderMode,\n\n    #[cfg(feature = \"hydration\")]\n    prepared_state: Option<String>,\n}\n\nimpl<COMP: BaseComponent> Context<COMP> {\n    /// The component scope\n    #[inline]\n    pub fn link(&self) -> &Scope<COMP> {\n        &self.scope\n    }\n\n    /// The component's props\n    #[inline]\n    pub fn props(&self) -> &COMP::Properties {\n        &self.props\n    }\n\n    #[cfg(feature = \"hydration\")]\n    pub(crate) fn creation_mode(&self) -> RenderMode {\n        self.creation_mode\n    }\n\n    /// The component's prepared state\n    pub fn prepared_state(&self) -> Option<&str> {\n        #[cfg(not(feature = \"hydration\"))]\n        let state = None;\n\n        #[cfg(feature = \"hydration\")]\n        let state = self.prepared_state.as_deref();\n\n        state\n    }\n}\n\n/// The common base of both function components and struct components.\n///\n/// If you are taken here by doc links, you might be looking for [`Component`] or\n/// [`#[component]`](crate::functional::component).\n///\n/// We provide a blanket implementation of this trait for every member that implements\n/// [`Component`].\n///\n/// # Warning\n///\n/// This trait may be subject to heavy changes between versions and is not intended for direct\n/// implementation.\n///\n/// You should used the [`Component`] trait or the\n/// [`#[component]`](crate::functional::component) macro to define your\n/// components.\npub trait BaseComponent: Sized + 'static {\n    /// The Component's Message.\n    type Message: 'static;\n\n    /// The Component's Properties.\n    type Properties: Properties;\n\n    /// Creates a component.\n    fn create(ctx: &Context<Self>) -> Self;\n\n    /// Updates component's internal state.\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool;\n\n    /// React to changes of component properties.\n    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool;\n\n    /// Returns a component layout to be rendered.\n    fn view(&self, ctx: &Context<Self>) -> HtmlResult;\n\n    /// Notified after a layout is rendered.\n    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool);\n\n    /// Notified before a component is destroyed.\n    fn destroy(&mut self, ctx: &Context<Self>);\n\n    /// Prepares the server-side state.\n    fn prepare_state(&self) -> Option<String>;\n}\n\n/// Components are the basic building blocks of the UI in a Yew app. Each Component\n/// chooses how to display itself using received props and self-managed state.\n/// Components can be dynamic and interactive by declaring messages that are\n/// triggered and handled asynchronously. This async update mechanism is inspired by\n/// Elm and the actor model used in the Actix framework.\npub trait Component: Sized + 'static {\n    /// Messages are used to make Components dynamic and interactive. Simple\n    /// Component's can declare their Message type to be `()`. Complex Component's\n    /// commonly use an enum to declare multiple Message types.\n    type Message: 'static;\n\n    /// The Component's properties.\n    ///\n    /// When the parent of a Component is re-rendered, it will either be re-created or\n    /// receive new properties in the context passed to the `changed` lifecycle method.\n    type Properties: Properties;\n\n    /// Called when component is created.\n    fn create(ctx: &Context<Self>) -> Self;\n\n    /// Called when a new message is sent to the component via its scope.\n    ///\n    /// Components handle messages in their `update` method and commonly use this method\n    /// to update their state and (optionally) re-render themselves.\n    ///\n    /// Returned bool indicates whether to render this Component after update.\n    ///\n    /// By default, this function will return true and thus make the component re-render.\n    #[allow(unused_variables)]\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        true\n    }\n\n    /// Called when properties passed to the component change\n    ///\n    /// Returned bool indicates whether to render this Component after changed.\n    ///\n    /// By default, this function will return true and thus make the component re-render.\n    #[allow(unused_variables)]\n    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {\n        true\n    }\n\n    /// Components define their visual layout using a JSX-style syntax through the use of the\n    /// `html!` procedural macro. The full guide to using the macro can be found in [Yew's\n    /// documentation](https://yew.rs/concepts/html).\n    ///\n    /// Note that `view()` calls do not always follow a render request from `update()` or\n    /// `changed()`. Yew may optimize some calls out to reduce virtual DOM tree generation overhead.\n    /// The `create()` call is always followed by a call to `view()`.\n    fn view(&self, ctx: &Context<Self>) -> Html;\n\n    /// The `rendered` method is called after each time a Component is rendered but\n    /// before the browser updates the page.\n    ///\n    /// Note that `rendered()` calls do not always follow a render request from `update()` or\n    /// `changed()`. Yew may optimize some calls out to reduce virtual DOM tree generation overhead.\n    /// The `create()` call is always followed by a call to `view()` and later `rendered()`.\n    #[allow(unused_variables)]\n    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {}\n\n    /// Prepares the state during server side rendering.\n    ///\n    /// This state will be sent to the client side and is available via `ctx.prepared_state()`.\n    ///\n    /// This method is only called during server-side rendering after the component has been\n    /// rendered.\n    fn prepare_state(&self) -> Option<String> {\n        None\n    }\n\n    /// Called right before a Component is unmounted.\n    #[allow(unused_variables)]\n    fn destroy(&mut self, ctx: &Context<Self>) {}\n}\n\nimpl<T> BaseComponent for T\nwhere\n    T: Sized + Component + 'static,\n{\n    type Message = <T as Component>::Message;\n    type Properties = <T as Component>::Properties;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Component::create(ctx)\n    }\n\n    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n        Component::update(self, ctx, msg)\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {\n        Component::changed(self, ctx, old_props)\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> HtmlResult {\n        Component::view(self, ctx).into_html_result()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {\n        Component::rendered(self, ctx, first_render)\n    }\n\n    fn destroy(&mut self, ctx: &Context<Self>) {\n        Component::destroy(self, ctx)\n    }\n\n    fn prepare_state(&self) -> Option<String> {\n        Component::prepare_state(self)\n    }\n}\n\n#[cfg(test)]\n#[cfg(any(feature = \"ssr\", feature = \"csr\"))]\nmod tests {\n    use super::*;\n\n    struct MyCustomComponent;\n\n    impl Component for MyCustomComponent {\n        type Message = ();\n        type Properties = ();\n\n        fn create(_ctx: &Context<Self>) -> Self {\n            Self\n        }\n\n        fn view(&self, _ctx: &Context<Self>) -> Html {\n            Default::default()\n        }\n    }\n\n    #[test]\n    fn make_sure_component_update_and_changed_rerender() {\n        let mut comp = MyCustomComponent;\n        let ctx = Context {\n            scope: Scope::new(None),\n            props: Rc::new(()),\n            #[cfg(feature = \"hydration\")]\n            creation_mode: crate::html::RenderMode::Hydration,\n            #[cfg(feature = \"hydration\")]\n            prepared_state: None,\n        };\n        assert!(Component::update(&mut comp, &ctx, ()));\n        assert!(Component::changed(&mut comp, &ctx, &Rc::new(())));\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/component/properties.rs",
    "content": "//! Component properties module\n\npub use yew_macro::Properties;\n\n/// Trait for building properties for a component\npub trait Properties: PartialEq {\n    /// Builder that will be used to construct properties\n    type Builder;\n\n    /// Entrypoint for building properties\n    fn builder() -> Self::Builder;\n}\n\n#[doc(hidden)]\nmod __macro {\n    /// A marker trait to ensure that the builder has received a specific required prop.\n    /// For each required impl in a property, we generate:\n    /// - a struct with the name of the prop, which takes the place of `P`.\n    /// - a token wrapper, `HasP<TokenTail>`, that records that the build state represented includes\n    ///   the state in `TokenTail` + `P`. Such tokens are returned from the setter on the builder,\n    ///   to verify the build state.\n    /// - An `impl<T> HasP<T>: HasProp<P, _>` saying that a state represented by a token of\n    ///   `HasP<_>` indeed verifies P has been set.\n    /// - An `impl<Q> HasP<Tail>: HasProp<Q, _> where Tail: HasProp<Q>` saying that any props set\n    ///   previously (represented by the tail) is still set after P has been set.\n    /// - ^ the two impls would be overlapping, where it not for the `How` argument, which resolves\n    ///   the conflict.\n    #[diagnostic::on_unimplemented(\n        message = \"property `{P}` is required but not provided\",\n        label = \"missing required property `{P}`\"\n    )]\n    pub trait HasProp<P, How> {}\n\n    /// A marker trait to ensure that the builder has received all required props.\n    /// For each struct deriving [`Properties`], an impl is generated, requiring `HasProp<p>` for\n    /// all properties marked as required as a bound on the impl.\n    ///\n    /// [`Properties`]: super::Properties\n    #[diagnostic::on_unimplemented(\n        message = \"not all required properties have been provided for `{P}`\",\n        label = \"missing required properties\"\n    )]\n    pub trait HasAllProps<P, How> {}\n\n    /// Trait finishing the builder and verifying all props were set.\n    /// The structure can be a bit surprising, and is related to how the proc macro reports errors\n    /// - why have a prepare_build method? This captures the argument types, but now `How`, and\n    ///   returns an internal type with a method that can be called without further qualification.\n    ///   We need the additional types, to avoid collision with property names in the Builder. We\n    ///   want to avoid qualification to persuade rust not to report the `finish_build` method name.\n    /// - why have a AllPropsFor trait? We want the trait to be on the Token, not on a type\n    ///   associated or derived from it, so that it shows up in errors directly instead of through\n    ///   convoluted traces.\n    pub trait Buildable<Token> {\n        /// Property type being built\n        type Output;\n        /// Instead of `Token` directly, a wrapped token type is checked for trait impls in macro\n        /// code. This avoids problems related to blanket impls.\n        type WrappedToken;\n        /// This method \"captures\" the builder and token type, but does not verify yet.\n        fn prepare_build(builder: Self, _: &Token) -> PreBuild<Token, Self>\n        where\n            Self: Sized,\n        {\n            PreBuild {\n                builder,\n                _token: std::marker::PhantomData,\n            }\n        }\n        /// Build the props from self. Expected to panic if not all props where set.\n        fn build(this: Self) -> Self::Output;\n    }\n    /// Helper alias for a Builder, also capturing the prop Token recording the provided props.\n    #[derive(Debug)]\n    pub struct PreBuild<Token, B> {\n        _token: std::marker::PhantomData<Token>,\n        builder: B,\n    }\n\n    impl<Token, B: Buildable<Token>> PreBuild<Token, B> {\n        /// This is the method that introduces the actual bound verifying all props where set.\n        pub fn build<How>(self) -> B::Output\n        where\n            Token: AllPropsFor<B, How>,\n        {\n            B::build(self.builder)\n        }\n    }\n\n    /// Trait to specify the requirement for Self to be a valid token signaling all props have been\n    /// provided to the builder.\n    #[diagnostic::on_unimplemented(\n        message = \"not all required properties have been provided\",\n        label = \"missing required properties for this component\"\n    )]\n    pub trait AllPropsFor<Builder, How> {}\n\n    impl<Token, Builder: Buildable<Token>, How> AllPropsFor<Builder, How> for Token where\n        Builder::WrappedToken: HasAllProps<Builder::Output, How>\n    {\n    }\n\n    /// Dummy struct targeted by assertions that all props were set\n    #[derive(Debug)]\n    pub struct AssertAllProps;\n\n    /// Builder for when a component has no properties\n    #[derive(Debug, PartialEq, Eq)]\n    pub struct EmptyBuilder;\n\n    impl super::Properties for () {\n        type Builder = EmptyBuilder;\n\n        fn builder() -> Self::Builder {\n            EmptyBuilder\n        }\n    }\n\n    impl<T> Buildable<T> for EmptyBuilder {\n        type Output = ();\n        type WrappedToken = ();\n\n        /// Build empty properties\n        fn build(_: Self) {}\n    }\n\n    impl<T> HasAllProps<(), T> for T {}\n}\n\n#[doc(hidden)]\npub use __macro::{AllPropsFor, AssertAllProps, Buildable, HasAllProps, HasProp};\n"
  },
  {
    "path": "packages/yew/src/html/component/scope.rs",
    "content": "//! Component scope module\n\nuse std::any::{Any, TypeId};\nuse std::future::Future;\nuse std::marker::PhantomData;\nuse std::ops::Deref;\nuse std::rc::Rc;\nuse std::{fmt, iter};\n\nuse futures::{Stream, StreamExt};\n\n#[cfg(any(feature = \"csr\", feature = \"ssr\"))]\nuse super::lifecycle::ComponentState;\nuse super::BaseComponent;\nuse crate::callback::Callback;\nuse crate::context::{ContextHandle, ContextProvider};\nuse crate::platform::spawn_local;\n#[cfg(any(feature = \"csr\", feature = \"ssr\"))]\nuse crate::scheduler::Shared;\n\n/// Untyped scope used for accessing parent scope\n#[derive(Clone)]\npub struct AnyScope {\n    type_id: TypeId,\n    parent: Option<Rc<AnyScope>>,\n    typed_scope: Rc<dyn Any>,\n}\n\nimpl fmt::Debug for AnyScope {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"AnyScope<_>\")\n    }\n}\n\nimpl<COMP: BaseComponent> From<Scope<COMP>> for AnyScope {\n    fn from(scope: Scope<COMP>) -> Self {\n        AnyScope {\n            type_id: TypeId::of::<COMP>(),\n            parent: scope.parent.clone(),\n            typed_scope: Rc::new(scope),\n        }\n    }\n}\n\nimpl AnyScope {\n    /// Returns the parent scope\n    pub fn get_parent(&self) -> Option<&AnyScope> {\n        self.parent.as_deref()\n    }\n\n    /// Returns the type of the linked component\n    pub fn get_type_id(&self) -> &TypeId {\n        &self.type_id\n    }\n\n    /// Attempts to downcast into a typed scope\n    ///\n    /// # Panics\n    ///\n    /// If the self value can't be cast into the target type.\n    pub fn downcast<COMP: BaseComponent>(&self) -> Scope<COMP> {\n        self.try_downcast::<COMP>().unwrap()\n    }\n\n    /// Attempts to downcast into a typed scope\n    ///\n    /// Returns [`None`] if the self value can't be cast into the target type.\n    pub fn try_downcast<COMP: BaseComponent>(&self) -> Option<Scope<COMP>> {\n        self.typed_scope.downcast_ref::<Scope<COMP>>().cloned()\n    }\n\n    /// Attempts to find a parent scope of a certain type\n    ///\n    /// Returns [`None`] if no parent scope with the specified type was found.\n    pub fn find_parent_scope<COMP: BaseComponent>(&self) -> Option<Scope<COMP>> {\n        iter::successors(Some(self), |scope| scope.get_parent())\n            .find_map(AnyScope::try_downcast::<COMP>)\n    }\n\n    /// Accesses a value provided by a parent `ContextProvider` component of the\n    /// same type.\n    pub fn context<T: Clone + PartialEq + 'static>(\n        &self,\n        callback: Callback<T>,\n    ) -> Option<(T, ContextHandle<T>)> {\n        let scope = self.find_parent_scope::<ContextProvider<T>>()?;\n        let scope_clone = scope.clone();\n        let component = scope.get_component()?;\n        Some(component.subscribe_consumer(callback, scope_clone))\n    }\n}\n\n/// A context which allows sending messages to a component.\npub struct Scope<COMP: BaseComponent> {\n    _marker: PhantomData<COMP>,\n    parent: Option<Rc<AnyScope>>,\n\n    #[cfg(any(feature = \"csr\", feature = \"ssr\"))]\n    pub(crate) pending_messages: MsgQueue<COMP::Message>,\n\n    #[cfg(any(feature = \"csr\", feature = \"ssr\"))]\n    pub(crate) state: Shared<Option<ComponentState>>,\n\n    pub(crate) id: usize,\n}\n\nimpl<COMP: BaseComponent> fmt::Debug for Scope<COMP> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"Scope<_>\")\n    }\n}\n\nimpl<COMP: BaseComponent> Clone for Scope<COMP> {\n    fn clone(&self) -> Self {\n        Scope {\n            _marker: PhantomData,\n\n            #[cfg(any(feature = \"csr\", feature = \"ssr\"))]\n            pending_messages: self.pending_messages.clone(),\n            parent: self.parent.clone(),\n\n            #[cfg(any(feature = \"csr\", feature = \"ssr\"))]\n            state: self.state.clone(),\n\n            id: self.id,\n        }\n    }\n}\n\nimpl<COMP: BaseComponent> Scope<COMP> {\n    /// Returns the parent scope\n    pub fn get_parent(&self) -> Option<&AnyScope> {\n        self.parent.as_deref()\n    }\n\n    /// Creates a `Callback` which will send a message to the linked\n    /// component's update method when invoked.\n    ///\n    /// If your callback function returns a [Future],\n    /// use [`callback_future`](Scope::callback_future) instead.\n    pub fn callback<F, IN, M>(&self, function: F) -> Callback<IN>\n    where\n        M: Into<COMP::Message>,\n        F: Fn(IN) -> M + 'static,\n    {\n        let scope = self.clone();\n        let closure = move |input| {\n            let output = function(input);\n            scope.send_message(output);\n        };\n        Callback::from(closure)\n    }\n\n    /// Creates a `Callback` which will send a batch of messages back\n    /// to the linked component's update method when invoked.\n    ///\n    /// The callback function's return type is generic to allow for dealing with both\n    /// `Option` and `Vec` nicely. `Option` can be used when dealing with a callback that\n    /// might not need to send an update.\n    ///\n    /// ```ignore\n    /// link.batch_callback(|_| vec![Msg::A, Msg::B]);\n    /// link.batch_callback(|_| Some(Msg::A));\n    /// ```\n    pub fn batch_callback<F, IN, OUT>(&self, function: F) -> Callback<IN>\n    where\n        F: Fn(IN) -> OUT + 'static,\n        OUT: SendAsMessage<COMP>,\n    {\n        let scope = self.clone();\n        let closure = move |input| {\n            let messages = function(input);\n            messages.send(&scope);\n        };\n        closure.into()\n    }\n\n    /// Accesses a value provided by a parent `ContextProvider` component of the\n    /// same type.\n    pub fn context<T: Clone + PartialEq + 'static>(\n        &self,\n        callback: Callback<T>,\n    ) -> Option<(T, ContextHandle<T>)> {\n        AnyScope::from(self.clone()).context(callback)\n    }\n\n    /// This method asynchronously awaits a [Future] that returns a message and sends it\n    /// to the linked component.\n    ///\n    /// # Panics\n    /// If the future panics, then the promise will not resolve, and will leak.\n    pub fn send_future<Fut, Msg>(&self, future: Fut)\n    where\n        Msg: Into<COMP::Message>,\n        Fut: Future<Output = Msg> + 'static,\n    {\n        let link = self.clone();\n        spawn_local(async move {\n            let message: COMP::Message = future.await.into();\n            link.send_message(message);\n        });\n    }\n\n    /// This method creates a [`Callback`] which, when emitted, asynchronously awaits the\n    /// message returned from the passed function before sending it to the linked component.\n    ///\n    /// # Panics\n    /// If the future panics, then the promise will not resolve, and will leak.\n    pub fn callback_future<F, Fut, IN, Msg>(&self, function: F) -> Callback<IN>\n    where\n        Msg: Into<COMP::Message>,\n        Fut: Future<Output = Msg> + 'static,\n        F: Fn(IN) -> Fut + 'static,\n    {\n        let link = self.clone();\n\n        let closure = move |input: IN| {\n            link.send_future(function(input));\n        };\n\n        closure.into()\n    }\n\n    /// Asynchronously send a batch of messages to a component. This asynchronously awaits the\n    /// passed [Future], before sending the message batch to the linked component.\n    ///\n    /// # Panics\n    /// If the future panics, then the promise will not resolve, and will leak.\n    pub fn send_future_batch<Fut>(&self, future: Fut)\n    where\n        Fut: Future + 'static,\n        Fut::Output: SendAsMessage<COMP>,\n    {\n        let link = self.clone();\n        let js_future = async move {\n            future.await.send(&link);\n        };\n        spawn_local(js_future);\n    }\n\n    /// This method asynchronously awaits a [`Stream`] that returns a series of messages and sends\n    /// them to the linked component.\n    ///\n    /// # Panics\n    /// If the stream panics, then the promise will not resolve, and will leak.\n    ///\n    /// # Note\n    ///\n    /// This method will not notify the component when the stream has been fully exhausted. If\n    /// you want this feature, you can add an EOF message variant for your component and use\n    /// [`StreamExt::chain`] and [`stream::once`](futures::stream::once) to chain an EOF message to\n    /// the original stream. If your stream is produced by another crate, you can use\n    /// [`StreamExt::map`] to transform the stream's item type to the component message type.\n    pub fn send_stream<S, M>(&self, stream: S)\n    where\n        M: Into<COMP::Message>,\n        S: Stream<Item = M> + 'static,\n    {\n        let link = self.clone();\n        let js_future = async move {\n            futures::pin_mut!(stream);\n            while let Some(msg) = stream.next().await {\n                let message: COMP::Message = msg.into();\n                link.send_message(message);\n            }\n        };\n        spawn_local(js_future);\n    }\n\n    /// Returns the linked component if available\n    pub fn get_component(&self) -> Option<impl Deref<Target = COMP> + '_> {\n        self.arch_get_component()\n    }\n\n    /// Send a message to the component.\n    pub fn send_message<T>(&self, msg: T)\n    where\n        T: Into<COMP::Message>,\n    {\n        self.arch_send_message(msg)\n    }\n\n    /// Send a batch of messages to the component.\n    ///\n    /// This is slightly more efficient than calling [`send_message`](Self::send_message)\n    /// in a loop.\n    pub fn send_message_batch(&self, messages: Vec<COMP::Message>) {\n        self.arch_send_message_batch(messages)\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use std::fmt::Write;\n\n    use super::*;\n    use crate::feat_ssr::VTagKind;\n    use crate::html::component::lifecycle::{\n        ComponentRenderState, CreateRunner, DestroyRunner, RenderRunner,\n    };\n    use crate::platform::fmt::BufWriter;\n    use crate::platform::pinned::oneshot;\n    use crate::scheduler;\n    use crate::virtual_dom::Collectable;\n\n    impl<COMP: BaseComponent> Scope<COMP> {\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            props: Rc<COMP::Properties>,\n            hydratable: bool,\n            parent_vtag_kind: VTagKind,\n        ) {\n            // Rust's Future implementation is stack-allocated and incurs zero runtime-cost.\n            //\n            // If the content of this channel is ready before it is awaited, it is\n            // similar to taking the value from a mutex lock.\n            let (tx, rx) = oneshot::channel();\n            let state = ComponentRenderState::Ssr { sender: Some(tx) };\n\n            scheduler::push_component_create(\n                self.id,\n                Box::new(CreateRunner {\n                    initial_render_state: state,\n                    props,\n                    scope: self.clone(),\n                    #[cfg(feature = \"hydration\")]\n                    prepared_state: None,\n                }),\n                Box::new(RenderRunner {\n                    state: self.state.clone(),\n                }),\n            );\n            scheduler::start();\n\n            let collectable = Collectable::for_component::<COMP>();\n\n            if hydratable {\n                collectable.write_open_tag(w);\n            }\n\n            let html = rx.await.unwrap();\n\n            let self_any_scope = AnyScope::from(self.clone());\n            html.render_into_stream(w, &self_any_scope, hydratable, parent_vtag_kind)\n                .await;\n\n            if let Some(prepared_state) = self.get_component().unwrap().prepare_state() {\n                let _ = w.write_str(r#\"<script type=\"application/x-yew-comp-state\">\"#);\n                let _ = w.write_str(&prepared_state);\n                let _ = w.write_str(r#\"</script>\"#);\n            }\n\n            if hydratable {\n                collectable.write_close_tag(w);\n            }\n\n            scheduler::push_component_destroy(Box::new(DestroyRunner {\n                state: self.state.clone(),\n                parent_to_detach: false,\n            }));\n            scheduler::start();\n        }\n    }\n}\n\n#[cfg(not(any(feature = \"ssr\", feature = \"csr\")))]\nmod feat_no_csr_ssr {\n    use super::*;\n\n    // Skeleton code to provide public methods when no renderer are enabled.\n    impl<COMP: BaseComponent> Scope<COMP> {\n        pub(super) fn arch_get_component(&self) -> Option<impl Deref<Target = COMP> + '_> {\n            Option::<&COMP>::None\n        }\n\n        pub(super) fn arch_send_message<T>(&self, _msg: T)\n        where\n            T: Into<COMP::Message>,\n        {\n        }\n\n        pub(super) fn arch_send_message_batch(&self, _messages: Vec<COMP::Message>) {}\n    }\n}\n\n#[cfg(any(feature = \"ssr\", feature = \"csr\"))]\nmod feat_csr_ssr {\n    use std::cell::{Ref, RefCell};\n    use std::sync::atomic::{AtomicUsize, Ordering};\n\n    use super::*;\n    use crate::html::component::lifecycle::UpdateRunner;\n    use crate::scheduler::{self, Shared};\n\n    #[derive(Debug)]\n    pub(crate) struct MsgQueue<Msg>(Shared<Vec<Msg>>);\n\n    impl<Msg> MsgQueue<Msg> {\n        pub fn new() -> Self {\n            MsgQueue(Rc::default())\n        }\n\n        pub fn push(&self, msg: Msg) -> usize {\n            let mut inner = self.0.borrow_mut();\n            inner.push(msg);\n\n            inner.len()\n        }\n\n        pub fn append(&self, other: &mut Vec<Msg>) -> usize {\n            let mut inner = self.0.borrow_mut();\n            inner.append(other);\n\n            inner.len()\n        }\n\n        pub fn drain(&self) -> Vec<Msg> {\n            let mut other_queue = Vec::new();\n            let mut inner = self.0.borrow_mut();\n\n            std::mem::swap(&mut *inner, &mut other_queue);\n\n            other_queue\n        }\n    }\n\n    impl<Msg> Clone for MsgQueue<Msg> {\n        fn clone(&self) -> Self {\n            MsgQueue(self.0.clone())\n        }\n    }\n\n    static COMP_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);\n\n    impl<COMP: BaseComponent> Scope<COMP> {\n        /// Crate a scope with an optional parent scope\n        pub(crate) fn new(parent: Option<AnyScope>) -> Self {\n            let parent = parent.map(Rc::new);\n\n            let state = Rc::new(RefCell::new(None));\n\n            let pending_messages = MsgQueue::new();\n\n            Scope {\n                _marker: PhantomData,\n\n                pending_messages,\n\n                state,\n                parent,\n\n                id: COMP_ID_COUNTER.fetch_add(1, Ordering::SeqCst),\n            }\n        }\n\n        #[inline]\n        pub(super) fn arch_get_component(&self) -> Option<impl Deref<Target = COMP> + '_> {\n            self.state.try_borrow().ok().and_then(|state_ref| {\n                Ref::filter_map(state_ref, |state| {\n                    state.as_ref().and_then(|m| m.downcast_comp_ref::<COMP>())\n                })\n                .ok()\n            })\n        }\n\n        #[inline]\n        fn schedule_update(&self) {\n            scheduler::push_component_update(Box::new(UpdateRunner {\n                state: self.state.clone(),\n            }));\n            // Not guaranteed to already have the scheduler started\n            scheduler::start();\n        }\n\n        #[inline]\n        pub(super) fn arch_send_message<T>(&self, msg: T)\n        where\n            T: Into<COMP::Message>,\n        {\n            // We are the first message in queue, so we queue the update.\n            if self.pending_messages.push(msg.into()) == 1 {\n                self.schedule_update();\n            }\n        }\n\n        #[inline]\n        pub(super) fn arch_send_message_batch(&self, mut messages: Vec<COMP::Message>) {\n            let msg_len = messages.len();\n\n            // The queue was empty, so we queue the update\n            if self.pending_messages.append(&mut messages) == msg_len {\n                self.schedule_update();\n            }\n        }\n    }\n}\n\n#[cfg(any(feature = \"ssr\", feature = \"csr\"))]\npub(crate) use feat_csr_ssr::*;\n\n#[cfg(feature = \"csr\")]\nmod feat_csr {\n    use std::cell::Ref;\n\n    use web_sys::Element;\n\n    use super::*;\n    use crate::dom_bundle::{BSubtree, Bundle, DomSlot, DynamicDomSlot};\n    use crate::html::component::lifecycle::{\n        ComponentRenderState, CreateRunner, DestroyRunner, PropsUpdateRunner, RenderRunner,\n    };\n    use crate::scheduler;\n\n    impl AnyScope {\n        #[cfg(any(test, feature = \"test\"))]\n        pub(crate) fn test() -> Self {\n            Self {\n                type_id: TypeId::of::<()>(),\n                parent: None,\n                typed_scope: Rc::new(()),\n            }\n        }\n    }\n\n    fn schedule_props_update(\n        state: Shared<Option<ComponentState>>,\n        props: Rc<dyn Any>,\n        next_sibling_slot: DomSlot,\n    ) {\n        scheduler::push_component_props_update(Box::new(PropsUpdateRunner {\n            state,\n            next_sibling_slot: Some(next_sibling_slot),\n            props: Some(props),\n        }));\n        // Not guaranteed to already have the scheduler started\n        scheduler::start();\n    }\n\n    impl<COMP> Scope<COMP>\n    where\n        COMP: BaseComponent,\n    {\n        /// Mounts a component with `props` to the specified `element` in the DOM.\n        pub(crate) fn mount_in_place(\n            &self,\n            root: BSubtree,\n            parent: Element,\n            slot: DomSlot,\n            props: Rc<COMP::Properties>,\n        ) -> DynamicDomSlot {\n            let bundle = Bundle::new();\n            let sibling_slot = DynamicDomSlot::new(slot);\n            let own_slot = DynamicDomSlot::new(sibling_slot.to_position());\n            let shared_slot = own_slot.clone();\n\n            let state = ComponentRenderState::Render {\n                bundle,\n                root,\n                own_slot,\n                parent,\n                sibling_slot,\n            };\n\n            scheduler::push_component_create(\n                self.id,\n                Box::new(CreateRunner {\n                    initial_render_state: state,\n                    props,\n                    scope: self.clone(),\n                    #[cfg(feature = \"hydration\")]\n                    prepared_state: None,\n                }),\n                Box::new(RenderRunner {\n                    state: self.state.clone(),\n                }),\n            );\n            // Not guaranteed to already have the scheduler started\n            scheduler::start();\n            shared_slot\n        }\n\n        pub(crate) fn reuse(&self, props: Rc<COMP::Properties>, slot: DomSlot) {\n            schedule_props_update(self.state.clone(), props, slot)\n        }\n    }\n\n    pub(crate) trait Scoped {\n        fn to_any(&self) -> AnyScope;\n        /// Get the render state if it hasn't already been destroyed\n        fn render_state(&self) -> Option<Ref<'_, ComponentRenderState>>;\n        /// Shift the node associated with this scope to a new place\n        fn shift_node(&self, parent: Element, slot: DomSlot);\n        /// Process an event to destroy a component\n        fn destroy(self, parent_to_detach: bool);\n        fn destroy_boxed(self: Box<Self>, parent_to_detach: bool);\n    }\n\n    impl<COMP: BaseComponent> Scoped for Scope<COMP> {\n        fn to_any(&self) -> AnyScope {\n            self.clone().into()\n        }\n\n        fn render_state(&self) -> Option<Ref<'_, ComponentRenderState>> {\n            let state_ref = self.state.borrow();\n\n            // check that component hasn't been destroyed\n            state_ref.as_ref()?;\n\n            Some(Ref::map(state_ref, |state_ref| {\n                &state_ref.as_ref().unwrap().render_state\n            }))\n        }\n\n        /// Process an event to destroy a component\n        fn destroy(self, parent_to_detach: bool) {\n            scheduler::push_component_destroy(Box::new(DestroyRunner {\n                state: self.state,\n                parent_to_detach,\n            }));\n            // Not guaranteed to already have the scheduler started\n            scheduler::start();\n        }\n\n        fn destroy_boxed(self: Box<Self>, parent_to_detach: bool) {\n            self.destroy(parent_to_detach)\n        }\n\n        fn shift_node(&self, parent: Element, slot: DomSlot) {\n            let mut state_ref = self.state.borrow_mut();\n            if let Some(render_state) = state_ref.as_mut() {\n                render_state.render_state.shift(parent, slot)\n            }\n        }\n    }\n}\n#[cfg(feature = \"csr\")]\npub(crate) use feat_csr::*;\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use wasm_bindgen::JsCast;\n    use web_sys::{Element, HtmlScriptElement};\n\n    use super::*;\n    use crate::dom_bundle::{BSubtree, DomSlot, DynamicDomSlot, Fragment};\n    use crate::html::component::lifecycle::{ComponentRenderState, CreateRunner, RenderRunner};\n    use crate::scheduler;\n    use crate::virtual_dom::Collectable;\n\n    impl<COMP> Scope<COMP>\n    where\n        COMP: BaseComponent,\n    {\n        /// Hydrates the component.\n        ///\n        /// Returns the position of the hydrated node in DOM.\n        ///\n        /// # Note\n        ///\n        /// This method is expected to collect all the elements belongs to the current component\n        /// immediately.\n        pub(crate) fn hydrate_in_place(\n            &self,\n            root: BSubtree,\n            parent: Element,\n            fragment: &mut Fragment,\n            props: Rc<COMP::Properties>,\n            prev_next_sibling: &mut Option<DynamicDomSlot>,\n        ) -> DynamicDomSlot {\n            // This is very helpful to see which component is failing during hydration\n            // which means this component may not having a stable layout / differs between\n            // client-side and server-side.\n            tracing::trace!(\n                component.id = self.id,\n                \"hydration(type = {})\",\n                std::any::type_name::<COMP>()\n            );\n\n            let collectable = Collectable::for_component::<COMP>();\n\n            let mut fragment = Fragment::collect_between(fragment, &collectable, &parent);\n\n            let prepared_state = match fragment\n                .back()\n                .cloned()\n                .and_then(|m| m.dyn_into::<HtmlScriptElement>().ok())\n            {\n                Some(m) if m.type_() == \"application/x-yew-comp-state\" => {\n                    fragment.pop_back();\n                    parent.remove_child(&m).unwrap();\n                    Some(m.text().unwrap())\n                }\n                _ => None,\n            };\n\n            let own_slot = match fragment.front().cloned() {\n                Some(first_node) => DynamicDomSlot::new(DomSlot::at(first_node)),\n                None => DynamicDomSlot::new(DomSlot::at_end()),\n            };\n            let shared_slot = own_slot.clone();\n            let sibling_slot = DynamicDomSlot::new_debug_trapped();\n            if let Some(prev_next_sibling) = prev_next_sibling {\n                prev_next_sibling.reassign(shared_slot.to_position());\n            }\n            *prev_next_sibling = Some(sibling_slot.clone());\n            let state = ComponentRenderState::Hydration {\n                parent,\n                root,\n                own_slot,\n                sibling_slot,\n                fragment,\n            };\n\n            scheduler::push_component_create(\n                self.id,\n                Box::new(CreateRunner {\n                    initial_render_state: state,\n                    props,\n                    scope: self.clone(),\n                    prepared_state,\n                }),\n                Box::new(RenderRunner {\n                    state: self.state.clone(),\n                }),\n            );\n\n            // Not guaranteed to already have the scheduler started\n            scheduler::start();\n            shared_slot\n        }\n    }\n}\n\n/// Defines a message type that can be sent to a component.\n/// Used for the return value of closure given to\n/// [Scope::batch_callback](struct.Scope.html#method.batch_callback).\npub trait SendAsMessage<COMP: BaseComponent> {\n    /// Sends the message to the given component's scope.\n    /// See [Scope::batch_callback](struct.Scope.html#method.batch_callback).\n    fn send(self, scope: &Scope<COMP>);\n}\n\nimpl<COMP> SendAsMessage<COMP> for Option<COMP::Message>\nwhere\n    COMP: BaseComponent,\n{\n    fn send(self, scope: &Scope<COMP>) {\n        if let Some(msg) = self {\n            scope.send_message(msg);\n        }\n    }\n}\n\nimpl<COMP> SendAsMessage<COMP> for Vec<COMP::Message>\nwhere\n    COMP: BaseComponent,\n{\n    fn send(self, scope: &Scope<COMP>) {\n        scope.send_message_batch(self);\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/conversion/into_prop_value.rs",
    "content": "use std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse implicit_clone::unsync::{IArray, IMap};\npub use implicit_clone::ImplicitClone;\n\nuse crate::callback::Callback;\nuse crate::html::{BaseComponent, ChildrenRenderer, Component, Scope};\nuse crate::virtual_dom::{AttrValue, VChild, VList, VNode, VText};\n\nimpl<Comp: Component> ImplicitClone for Scope<Comp> {}\n// TODO there are still a few missing\n\n/// A trait similar to `Into<T>` which allows conversion to a value of a `Properties` struct.\npub trait IntoPropValue<T> {\n    /// Convert `self` to a value of a `Properties` struct.\n    fn into_prop_value(self) -> T;\n}\n\nimpl<T> IntoPropValue<T> for T {\n    #[inline]\n    fn into_prop_value(self) -> T {\n        self\n    }\n}\n\nimpl<T> IntoPropValue<T> for &T\nwhere\n    T: ImplicitClone,\n{\n    #[inline]\n    fn into_prop_value(self) -> T {\n        self.clone()\n    }\n}\n\nimpl<T> IntoPropValue<Option<T>> for T {\n    #[inline]\n    fn into_prop_value(self) -> Option<T> {\n        Some(self)\n    }\n}\n\nimpl<T> IntoPropValue<Option<T>> for &T\nwhere\n    T: ImplicitClone,\n{\n    #[inline]\n    fn into_prop_value(self) -> Option<T> {\n        Some(self.clone())\n    }\n}\n\nimpl<I, O, F> IntoPropValue<Callback<I, O>> for F\nwhere\n    F: 'static + Fn(I) -> O,\n{\n    #[inline]\n    fn into_prop_value(self) -> Callback<I, O> {\n        Callback::from(self)\n    }\n}\n\nimpl<I, O, F> IntoPropValue<Option<Callback<I, O>>> for F\nwhere\n    F: 'static + Fn(I) -> O,\n{\n    #[inline]\n    fn into_prop_value(self) -> Option<Callback<I, O>> {\n        Some(Callback::from(self))\n    }\n}\n\nimpl<I, O, F> IntoPropValue<Option<Callback<I, O>>> for Option<F>\nwhere\n    F: 'static + Fn(I) -> O,\n{\n    #[inline]\n    fn into_prop_value(self) -> Option<Callback<I, O>> {\n        self.map(Callback::from)\n    }\n}\n\nimpl<T, C> IntoPropValue<ChildrenRenderer<C>> for VChild<T>\nwhere\n    T: BaseComponent,\n    C: Clone + Into<VNode>,\n    VChild<T>: Into<C>,\n{\n    #[inline]\n    fn into_prop_value(self) -> ChildrenRenderer<C> {\n        ChildrenRenderer::new(vec![self.into()])\n    }\n}\n\nimpl<T, C> IntoPropValue<Option<ChildrenRenderer<C>>> for VChild<T>\nwhere\n    T: BaseComponent,\n    C: Clone + Into<VNode>,\n    VChild<T>: Into<C>,\n{\n    #[inline]\n    fn into_prop_value(self) -> Option<ChildrenRenderer<C>> {\n        Some(ChildrenRenderer::new(vec![self.into()]))\n    }\n}\n\nimpl<T, C> IntoPropValue<Option<ChildrenRenderer<C>>> for Option<VChild<T>>\nwhere\n    T: BaseComponent,\n    C: Clone + Into<VNode>,\n    VChild<T>: Into<C>,\n{\n    #[inline]\n    fn into_prop_value(self) -> Option<ChildrenRenderer<C>> {\n        self.map(|m| ChildrenRenderer::new(vec![m.into()]))\n    }\n}\n\nimpl<T, R> IntoPropValue<ChildrenRenderer<R>> for Vec<T>\nwhere\n    T: Into<R>,\n    R: Clone + Into<VNode>,\n{\n    #[inline]\n    fn into_prop_value(self) -> ChildrenRenderer<R> {\n        ChildrenRenderer::new(self.into_iter().map(|m| m.into()).collect::<Vec<_>>())\n    }\n}\n\nimpl<T> IntoPropValue<VNode> for VChild<T>\nwhere\n    T: BaseComponent,\n{\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::from(self)\n    }\n}\n\nimpl IntoPropValue<VNode> for VList {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::VList(Rc::new(self))\n    }\n}\nimpl IntoPropValue<VNode> for VText {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::VText(self)\n    }\n}\n\nimpl IntoPropValue<VNode> for () {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::default()\n    }\n}\n\nimpl IntoPropValue<VNode> for ChildrenRenderer<VNode> {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::VList(Rc::new(self.into()))\n    }\n}\n\nimpl IntoPropValue<VNode> for &ChildrenRenderer<VNode> {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::VList(Rc::new(VList::from(self.children.clone())))\n    }\n}\n\nimpl IntoPropValue<ChildrenRenderer<VNode>> for VNode {\n    #[inline]\n    fn into_prop_value(self) -> ChildrenRenderer<VNode> {\n        ChildrenRenderer::new(vec![self])\n    }\n}\n\nimpl IntoPropValue<ChildrenRenderer<VNode>> for VText {\n    #[inline]\n    fn into_prop_value(self) -> ChildrenRenderer<VNode> {\n        ChildrenRenderer::new(vec![self.into()])\n    }\n}\n\nimpl IntoPropValue<VList> for ChildrenRenderer<VNode> {\n    #[inline]\n    fn into_prop_value(self) -> VList {\n        VList::from(self.children)\n    }\n}\n\nimpl<C: BaseComponent> IntoPropValue<VList> for VChild<C> {\n    #[inline]\n    fn into_prop_value(self) -> VList {\n        VList::from(VNode::from(self))\n    }\n}\n\nimpl IntoPropValue<ChildrenRenderer<VNode>> for AttrValue {\n    fn into_prop_value(self) -> ChildrenRenderer<VNode> {\n        ChildrenRenderer::new(vec![VNode::VText(VText::new(self))])\n    }\n}\n\nimpl IntoPropValue<VNode> for Vec<VNode> {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        VNode::VList(Rc::new(VList::from(self)))\n    }\n}\n\nimpl<T: IntoPropValue<VNode>> IntoPropValue<VNode> for Option<T> {\n    #[inline]\n    fn into_prop_value(self) -> VNode {\n        self.map(IntoPropValue::into_prop_value).unwrap_or_default()\n    }\n}\n\nmacro_rules! impl_into_prop {\n    (|$value:ident: $from_ty:ty| -> $to_ty:ty { $conversion:expr }) => {\n        // implement V -> T\n        impl IntoPropValue<$to_ty> for $from_ty {\n            #[inline]\n            fn into_prop_value(self) -> $to_ty {\n                let $value = self;\n                $conversion\n            }\n        }\n        // implement V -> Option<T>\n        impl IntoPropValue<Option<$to_ty>> for $from_ty {\n            #[inline]\n            fn into_prop_value(self) -> Option<$to_ty> {\n                let $value = self;\n                Some({ $conversion })\n            }\n        }\n        // implement Option<V> -> Option<T>\n        impl IntoPropValue<Option<$to_ty>> for Option<$from_ty> {\n            #[inline]\n            fn into_prop_value(self) -> Option<$to_ty> {\n                self.map(IntoPropValue::into_prop_value)\n            }\n        }\n    };\n}\n\n// implemented with literals in mind\nimpl_into_prop!(|value: &'static str| -> String { value.to_owned() });\nimpl_into_prop!(|value: &'static str| -> AttrValue { AttrValue::Static(value) });\nimpl_into_prop!(|value: String| -> AttrValue { AttrValue::Rc(Rc::from(value)) });\nimpl_into_prop!(|value: Rc<str>| -> AttrValue { AttrValue::Rc(value) });\nimpl_into_prop!(|value: Cow<'static, str>| -> AttrValue { AttrValue::from(value) });\n\nimpl<T: ImplicitClone + 'static> IntoPropValue<IArray<T>> for &'static [T] {\n    fn into_prop_value(self) -> IArray<T> {\n        IArray::from(self)\n    }\n}\n\nimpl<T: ImplicitClone + 'static> IntoPropValue<IArray<T>> for Vec<T> {\n    fn into_prop_value(self) -> IArray<T> {\n        IArray::from(self)\n    }\n}\n\nimpl<K: Eq + std::hash::Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>\n    IntoPropValue<IMap<K, V>> for &'static [(K, V)]\n{\n    fn into_prop_value(self) -> IMap<K, V> {\n        IMap::from(self)\n    }\n}\n\nimpl<K: Eq + std::hash::Hash + ImplicitClone + 'static, V: PartialEq + ImplicitClone + 'static>\n    IntoPropValue<IMap<K, V>> for indexmap::IndexMap<K, V>\n{\n    fn into_prop_value(self) -> IMap<K, V> {\n        IMap::from(self)\n    }\n}\n\nmacro_rules! impl_into_prop_value_via_display {\n    ($from_ty: ty) => {\n        impl IntoPropValue<VNode> for $from_ty {\n            #[inline(always)]\n            fn into_prop_value(self) -> VNode {\n                VText::from(self).into()\n            }\n        }\n        impl IntoPropValue<VNode> for &$from_ty {\n            #[inline(always)]\n            fn into_prop_value(self) -> VNode {\n                self.clone().into_prop_value()\n            }\n        }\n        impl IntoPropValue<Option<VNode>> for $from_ty {\n            #[inline(always)]\n            fn into_prop_value(self) -> Option<VNode> {\n                Some(IntoPropValue::<VNode>::into_prop_value(self))\n            }\n        }\n        impl IntoPropValue<Option<VNode>> for &$from_ty {\n            #[inline(always)]\n            fn into_prop_value(self) -> Option<VNode> {\n                Some(IntoPropValue::<VNode>::into_prop_value(self))\n            }\n        }\n        impl IntoPropValue<Option<VNode>> for Option<$from_ty> {\n            #[inline(always)]\n            fn into_prop_value(self) -> Option<VNode> {\n                self.map(IntoPropValue::<VNode>::into_prop_value)\n            }\n        }\n    };\n}\n\n// go through AttrValue::from where possible\nmacro_rules! impl_into_prop_value_via_attr_value {\n    ($from_ty: ty) => {\n        impl IntoPropValue<VNode> for $from_ty {\n            #[inline(always)]\n            fn into_prop_value(self) -> VNode {\n                VText::new(self).into()\n            }\n        }\n        impl IntoPropValue<Option<VNode>> for $from_ty {\n            #[inline(always)]\n            fn into_prop_value(self) -> Option<VNode> {\n                Some(VText::new(self).into())\n            }\n        }\n        impl IntoPropValue<Option<VNode>> for Option<$from_ty> {\n            #[inline(always)]\n            fn into_prop_value(self) -> Option<VNode> {\n                self.map(|v| VText::new(v).into())\n            }\n        }\n    };\n}\n\n// These are a selection of types implemented via display.\nimpl_into_prop_value_via_display!(bool);\nimpl_into_prop_value_via_display!(char);\nimpl_into_prop_value_via_display!(&String);\nimpl_into_prop_value_via_display!(&str);\nimpl_into_prop_value_via_display!(Arc<str>);\nimpl_into_prop_value_via_display!(Arc<String>);\nimpl_into_prop_value_via_display!(Rc<String>);\nimpl_into_prop_value_via_display!(u8);\nimpl_into_prop_value_via_display!(u16);\nimpl_into_prop_value_via_display!(u32);\nimpl_into_prop_value_via_display!(u64);\nimpl_into_prop_value_via_display!(u128);\nimpl_into_prop_value_via_display!(usize);\nimpl_into_prop_value_via_display!(i8);\nimpl_into_prop_value_via_display!(i16);\nimpl_into_prop_value_via_display!(i32);\nimpl_into_prop_value_via_display!(i64);\nimpl_into_prop_value_via_display!(i128);\nimpl_into_prop_value_via_display!(isize);\nimpl_into_prop_value_via_display!(f32);\nimpl_into_prop_value_via_display!(f64);\n\nimpl_into_prop_value_via_attr_value!(String);\nimpl_into_prop_value_via_attr_value!(AttrValue);\nimpl_into_prop_value_via_attr_value!(&AttrValue);\nimpl_into_prop_value_via_attr_value!(Rc<str>);\nimpl_into_prop_value_via_attr_value!(Cow<'static, str>);\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_str() {\n        let _: String = \"foo\".into_prop_value();\n        let _: Option<String> = \"foo\".into_prop_value();\n        let _: AttrValue = \"foo\".into_prop_value();\n        let _: Option<AttrValue> = \"foo\".into_prop_value();\n        let _: Option<AttrValue> = Rc::<str>::from(\"foo\").into_prop_value();\n        let _: Option<AttrValue> = Cow::Borrowed(\"foo\").into_prop_value();\n    }\n\n    #[test]\n    fn test_option_to_vnode() {\n        let _: VNode = Some(String::from(\"hello\")).into_prop_value();\n        let _: VNode = Some(AttrValue::Static(\"hello\")).into_prop_value();\n        let _: VNode = Option::<String>::None.into_prop_value();\n        let _: VNode = Option::<AttrValue>::None.into_prop_value();\n        let _: VNode = Some(VNode::default()).into_prop_value();\n        let _: VNode = Option::<VNode>::None.into_prop_value();\n        let _: VNode = Some(42u32).into_prop_value();\n        let _: VNode = Some(true).into_prop_value();\n    }\n\n    #[test]\n    fn test_into_option_vnode() {\n        // T -> Option<VNode>\n        let _: Option<VNode> = \"hello\".into_prop_value();\n        let _: Option<VNode> = String::from(\"hello\").into_prop_value();\n        let _: Option<VNode> = AttrValue::Static(\"hello\").into_prop_value();\n        let _: Option<VNode> = 42u32.into_prop_value();\n        let _: Option<VNode> = true.into_prop_value();\n        // &T -> Option<VNode>\n        let _: Option<VNode> = (&42u32).into_prop_value();\n        let _: Option<VNode> = (&true).into_prop_value();\n        let s = String::from(\"hello\");\n        let _: Option<VNode> = (&s).into_prop_value();\n        // Option<T> -> Option<VNode>\n        let _: Option<VNode> = Some(\"hello\").into_prop_value();\n        let _: Option<VNode> = Option::<&str>::None.into_prop_value();\n        let _: Option<VNode> = Some(String::from(\"hello\")).into_prop_value();\n        let _: Option<VNode> = Option::<String>::None.into_prop_value();\n        let _: Option<VNode> = Some(42u32).into_prop_value();\n        let _: Option<VNode> = Some(true).into_prop_value();\n    }\n\n    #[test]\n    fn test_ref_to_vnode() {\n        let _: VNode = (&42i32).into_prop_value();\n        let _: VNode = (&true).into_prop_value();\n        let _: VNode = (&1.5f64).into_prop_value();\n        let s = String::from(\"hello\");\n        let _: VNode = (&s).into_prop_value();\n        let a = AttrValue::Static(\"hello\");\n        let _: VNode = (&a).into_prop_value();\n        let sr: &str = \"hello\";\n        let _: VNode = (&sr).into_prop_value();\n    }\n\n    #[test]\n    fn test_callback() {\n        let _: Callback<String> = (|_: String| ()).into_prop_value();\n        let _: Option<Callback<String>> = (|_: String| ()).into_prop_value();\n        let _: Option<Callback<String>> = Some(|_: String| ()).into_prop_value();\n        let _: Callback<String, String> = (|s: String| s).into_prop_value();\n        let _: Option<Callback<String, String>> = (|s: String| s).into_prop_value();\n        let _: Option<Callback<String, String>> = Some(|s: String| s).into_prop_value();\n    }\n\n    #[test]\n    fn test_html_to_children_compiles() {\n        use crate::prelude::*;\n\n        #[derive(Clone, Debug, PartialEq, Properties)]\n        pub struct Props {\n            #[prop_or_default]\n            pub header: Children,\n            #[prop_or_default]\n            pub children: Children,\n            #[prop_or_default]\n            pub footer: Children,\n        }\n\n        #[component]\n        pub fn App(props: &Props) -> Html {\n            let Props {\n                header,\n                children,\n                footer,\n            } = props.clone();\n\n            html! {\n                <div>\n                    <header>\n                        {header}\n                    </header>\n                    <main>\n                        {children}\n                    </main>\n                    <footer>\n                        {footer}\n                    </footer>\n                </div>\n            }\n        }\n\n        let header = html! { <div>{\"header\"}</div> };\n        let footer = html! { <div>{\"footer\"}</div> };\n        let children = html! { <div>{\"main\"}</div> };\n\n        let _ = html! {\n            <App {header} {footer}>\n                {children}\n            </App>\n        };\n    }\n\n    #[test]\n    fn test_vchild_to_children_with_props_compiles() {\n        use crate::prelude::*;\n\n        #[component]\n        pub fn Comp() -> Html {\n            Html::default()\n        }\n\n        #[derive(Clone, Debug, PartialEq, Properties)]\n        pub struct Props {\n            #[prop_or_default]\n            pub header: ChildrenWithProps<Comp>,\n            #[prop_or_default]\n            pub children: Children,\n            #[prop_or_default]\n            pub footer: ChildrenWithProps<Comp>,\n        }\n\n        #[component]\n        pub fn App(props: &Props) -> Html {\n            let Props {\n                header,\n                children,\n                footer,\n            } = props.clone();\n\n            html! {\n                <div>\n                    <header>\n                        {for header}\n                    </header>\n                    <main>\n                        {children}\n                    </main>\n                    <footer>\n                        {for footer}\n                    </footer>\n                </div>\n            }\n        }\n\n        let header = VChild::new((), None);\n        let footer = html_nested! { <Comp /> };\n        let children = html! { <div>{\"main\"}</div> };\n\n        let _ = html! {\n            <App {header} {footer}>\n                {children}\n            </App>\n        };\n    }\n\n    #[test]\n    fn test_vlist_to_children_compiles() {\n        use crate::prelude::*;\n        use crate::virtual_dom::VList;\n\n        #[component]\n        fn Foo() -> Html {\n            todo!()\n        }\n\n        #[derive(PartialEq, Properties)]\n        pub struct ChildProps {\n            #[prop_or_default]\n            pub children: Html,\n        }\n\n        #[component]\n        fn Child(_props: &ChildProps) -> Html {\n            html!()\n        }\n\n        #[derive(PartialEq, Properties)]\n        pub struct ParentProps {\n            pub children: VList,\n        }\n\n        #[component]\n        fn Parent(_props: &ParentProps) -> Html {\n            todo!()\n        }\n\n        let _ = html! {\n            <Parent>\n                <Child></Child>\n            </Parent>\n        };\n\n        let _ = html! {\n            <Parent>\n                <Child />\n                <Child />\n            </Parent>\n        };\n\n        let _ = html! {\n            <Parent>\n                <Child>\n                    <Foo />\n                </Child>\n            </Parent>\n        };\n    }\n\n    #[test]\n    fn attr_value_children() {\n        use crate::prelude::*;\n\n        #[derive(PartialEq, Properties)]\n        pub struct ChildProps {\n            #[prop_or_default]\n            pub children: AttrValue,\n        }\n\n        #[component]\n        fn Child(_props: &ChildProps) -> Html {\n            html!()\n        }\n        {\n            let attr_value = AttrValue::from(\"foo\");\n\n            let _ = html! { <Child>{attr_value}</Child> };\n        }\n        {\n            let attr_value = AttrValue::from(\"foo\");\n\n            let _ = html! { <Child>{&attr_value}</Child> };\n        }\n    }\n\n    #[test]\n    fn test_bare_none_option_string_prop() {\n        use crate::prelude::*;\n\n        #[derive(PartialEq, Properties)]\n        pub struct Props {\n            pub foo: Option<String>,\n        }\n\n        #[component]\n        fn Comp(_props: &Props) -> Html {\n            html! {}\n        }\n\n        let _ = html! { <Comp foo={None} /> };\n        let _ = html! { <Comp foo=\"hello\" /> };\n        let _ = html! { <Comp foo={Some(\"hello\")} /> };\n    }\n\n    #[test]\n    fn test_bare_none_option_attr_value_prop() {\n        use crate::prelude::*;\n\n        #[derive(PartialEq, Properties)]\n        pub struct Props {\n            pub foo: Option<AttrValue>,\n        }\n\n        #[component]\n        fn Comp(_props: &Props) -> Html {\n            html! {}\n        }\n\n        let _ = html! { <Comp foo={None} /> };\n        let _ = html! { <Comp foo=\"hello\" /> };\n        let _ = html! { <Comp foo={AttrValue::from(\"hello\")} /> };\n    }\n\n    #[test]\n    fn test_bare_none_option_html_prop() {\n        use crate::prelude::*;\n\n        #[derive(PartialEq, Properties)]\n        pub struct Props {\n            pub title: Option<Html>,\n        }\n\n        #[component]\n        fn Comp(_props: &Props) -> Html {\n            html! {}\n        }\n\n        let _ = html! { <Comp title={None} /> };\n        let _ = html! { <Comp title={Option::<Html>::None} /> };\n    }\n\n    #[test]\n    fn test_bare_none_optional_prop_with_default() {\n        use crate::prelude::*;\n\n        #[derive(PartialEq, Properties)]\n        pub struct Props {\n            #[prop_or_default]\n            pub foo: Option<String>,\n        }\n\n        #[component]\n        fn Comp(_props: &Props) -> Html {\n            html! {}\n        }\n\n        let _ = html! { <Comp foo={None} /> };\n        let _ = html! { <Comp foo=\"hello\" /> };\n        let _ = html! { <Comp /> };\n    }\n\n    #[test]\n    fn test_option_html_prop_compiles() {\n        use crate::prelude::*;\n\n        #[derive(PartialEq, Properties)]\n        pub struct Props {\n            pub title: Option<Html>,\n        }\n\n        #[component]\n        fn Foo(props: &Props) -> Html {\n            match &props.title {\n                Some(title) => html! { <h1>{ title.clone() }</h1> },\n                None => html! {},\n            }\n        }\n\n        let _ = html! { <Foo title=\"Title\" /> };\n\n        let _ = html! { <Foo title={String::from(\"Title\")} /> };\n\n        let _ = html! { <Foo title={Some(\"Title\")} /> };\n\n        let _ = html! { <Foo title={Option::<Html>::None} /> };\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/conversion/mod.rs",
    "content": "mod into_prop_value;\npub use into_prop_value::*;\n"
  },
  {
    "path": "packages/yew/src/html/error.rs",
    "content": "use thiserror::Error;\n\nuse crate::suspense::Suspension;\n\n/// Render Error.\n#[derive(Error, Debug, Clone, PartialEq)]\npub enum RenderError {\n    /// Component Rendering Suspended\n    #[error(\"component rendering is suspended.\")]\n    Suspended(#[from] Suspension),\n}\n\n/// Render Result.\npub type RenderResult<T> = std::result::Result<T, RenderError>;\n"
  },
  {
    "path": "packages/yew/src/html/listener/events.rs",
    "content": "// Inspired by: http://package.elm-lang.org/packages/elm-lang/html/2.0.0/Html-Events\n\nmacro_rules! impl_action {\n    ($($action:ident($type:ident) -> $ret:path => $convert:path)*) => {$(\n        impl_action!($action($type, false) -> $ret => $convert);\n    )*};\n    ($($action:ident($type:ident, $passive:literal) -> $ret:path => $convert:path)*) => {$(\n        /// An abstract implementation of a listener.\n        #[doc(hidden)]\n        pub mod $action {\n            use crate::callback::Callback;\n            use crate::virtual_dom::{Listener, ListenerKind};\n            use std::rc::Rc;\n\n            /// A wrapper for a callback which attaches event listeners to elements.\n            #[derive(Clone, Debug)]\n            pub struct Wrapper {\n                callback: Callback<Event>,\n            }\n\n            impl Wrapper {\n                /// Create a wrapper for an event-typed callback\n                pub fn new(callback: Callback<Event>) -> Self {\n                    Wrapper { callback }\n                }\n\n                #[doc(hidden)]\n                #[inline]\n                pub fn __macro_new(\n                    callback: impl crate::html::IntoEventCallback<Event>,\n                ) -> Option<Rc<dyn Listener>> {\n                    let callback = callback.into_event_callback()?;\n                    Some(Rc::new(Self::new(callback)))\n                }\n            }\n\n            /// And event type which keeps the returned type.\n            pub type Event = $ret;\n\n            impl Listener for Wrapper {\n                fn kind(&self) -> ListenerKind {\n                    ListenerKind::$action\n                }\n\n                fn handle(&self, event: web_sys::Event) {\n                    self.callback.emit($convert(event));\n                }\n\n                fn passive(&self) -> bool {\n                    $passive\n                }\n            }\n        }\n    )*};\n}\n\n// Reduces repetition for common cases\nmacro_rules! impl_short {\n    ($($action:ident)*) => {\n        impl_action! {\n            $(\n                $action(Event) -> web_sys::Event => std::convert::identity\n            )*\n        }\n    };\n    ($($action:ident($type:ident))*) => {\n        impl_action! {\n            $(\n                $action($type) -> web_sys::$type  => crate::html::listener::cast_event\n            )*\n        }\n    };\n}\n\n// Unspecialized event type\nimpl_short! {\n    onabort\n    oncancel\n    oncanplay\n    oncanplaythrough\n    onclose\n    oncuechange\n    ondurationchange\n    onemptied\n    onended\n    onerror\n    onformdata  // web_sys doesn't have a struct for `FormDataEvent`\n    oninvalid\n\n    onload\n    onloadeddata\n    onloadedmetadata\n\n    onpause\n    onplay\n    onplaying\n\n    onratechange\n    onreset\n    onresize\n    onsecuritypolicyviolation\n\n    onseeked\n    onseeking\n\n    onselect\n    onslotchange\n    onstalled\n    onsuspend\n    ontimeupdate\n    ontoggle\n    onvolumechange\n    onwaiting\n\n    onchange\n\n    oncopy\n    oncut\n    onpaste\n\n    onpointerlockchange\n    onpointerlockerror\n    onselectionchange\n    onselectstart\n    onshow\n}\n\n// Specialized event type\nimpl_short! {\n    onauxclick(MouseEvent)\n    onclick(MouseEvent)\n\n    oncontextmenu(MouseEvent)\n    ondblclick(MouseEvent)\n\n    ondrag(DragEvent)\n    ondragend(DragEvent)\n    ondragenter(DragEvent)\n    ondragexit(DragEvent)\n    ondragleave(DragEvent)\n    ondragover(DragEvent)\n    ondragstart(DragEvent)\n    ondrop(DragEvent)\n\n    onblur(FocusEvent)\n    onfocus(FocusEvent)\n    onfocusin(FocusEvent)\n    onfocusout(FocusEvent)\n\n    onkeydown(KeyboardEvent)\n    onkeypress(KeyboardEvent)\n    onkeyup(KeyboardEvent)\n\n    onloadstart(ProgressEvent)\n    onprogress(ProgressEvent)\n    onloadend(ProgressEvent)\n\n    onmousedown(MouseEvent)\n    onmouseenter(MouseEvent)\n    onmouseleave(MouseEvent)\n    onmousemove(MouseEvent)\n    onmouseout(MouseEvent)\n    onmouseover(MouseEvent)\n    onmouseup(MouseEvent)\n    onwheel(WheelEvent)\n\n    oninput(InputEvent)\n\n    onsubmit(SubmitEvent)\n\n    onanimationcancel(AnimationEvent)\n    onanimationend(AnimationEvent)\n    onanimationiteration(AnimationEvent)\n    onanimationstart(AnimationEvent)\n\n    ongotpointercapture(PointerEvent)\n    onlostpointercapture(PointerEvent)\n    onpointercancel(PointerEvent)\n    onpointerdown(PointerEvent)\n    onpointerenter(PointerEvent)\n    onpointerleave(PointerEvent)\n    onpointermove(PointerEvent)\n    onpointerout(PointerEvent)\n    onpointerover(PointerEvent)\n    onpointerup(PointerEvent)\n\n    ontouchcancel(TouchEvent)\n    ontouchend(TouchEvent)\n\n    ontransitioncancel(TransitionEvent)\n    ontransitionend(TransitionEvent)\n    ontransitionrun(TransitionEvent)\n    ontransitionstart(TransitionEvent)\n}\n\nmacro_rules! impl_passive {\n    ($($action:ident($type:ident))*) => {\n        impl_action! {\n            $(\n                $action($type, true) -> web_sys::$type\n                    => crate::html::listener::cast_event\n            )*\n        }\n    };\n}\n\n// Best used with passive listeners for responsiveness\nimpl_passive! {\n    onscroll(Event)\n\n    ontouchmove(TouchEvent)\n    ontouchstart(TouchEvent)\n}\n"
  },
  {
    "path": "packages/yew/src/html/listener/mod.rs",
    "content": "#[macro_use]\nmod events;\n\npub use events::*;\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget};\n\nuse crate::Callback;\n\n/// Cast [Event] `e` into it's target `T`.\n///\n/// This function mainly exists to provide type inference in the [impl_action] macro to the compiler\n/// and avoid some verbosity by not having to type the signature over and over in closure\n/// definitions.\n#[inline]\npub(crate) fn cast_event<T>(e: Event) -> T\nwhere\n    T: JsCast,\n{\n    e.unchecked_into()\n}\n\n/// A trait to obtain a generic event target.\n///\n/// The methods in this trait are convenient helpers that use the [`JsCast`] trait internally\n/// to do the conversion.\npub trait TargetCast\nwhere\n    Self: AsRef<Event>,\n{\n    /// Performs a dynamic cast (checked at runtime) of this events target into the type `T`.\n    ///\n    /// This method can return [`None`] for two reasons:\n    /// - The event's target was [`None`]\n    /// - The event's target type did not match `T`\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use web_sys::HtmlTextAreaElement;\n    /// use yew::prelude::*;\n    /// # enum Msg {\n    /// #   Value(String),\n    /// # }\n    /// # struct Comp;\n    /// # impl Component for Comp {\n    /// # type Message = Msg;\n    /// # type Properties = ();\n    /// # fn create(ctx: &Context<Self>) -> Self {\n    /// #   Self\n    /// # }\n    ///\n    /// fn view(&self, ctx: &Context<Self>) -> Html {\n    ///     html! {\n    ///         <div\n    ///             onchange={ctx.link().batch_callback(|e: Event| {\n    ///                 if let Some(input) = e.target_dyn_into::<HtmlTextAreaElement>() {\n    ///                     Some(Msg::Value(input.value()))\n    ///                 } else {\n    ///                     None\n    ///                 }\n    ///             })}\n    ///         >\n    ///             <textarea />\n    ///             <input type=\"text\" />\n    ///         </div>\n    ///     }\n    /// }\n    /// # }\n    /// ```\n    /// _Note: if you can apply the [`Callback`] directly onto an element which doesn't have a child\n    /// consider using [`TargetCast::target_unchecked_into<T>`]_\n    #[inline]\n    fn target_dyn_into<T>(&self) -> Option<T>\n    where\n        T: AsRef<EventTarget> + JsCast,\n    {\n        self.as_ref()\n            .target()\n            .and_then(|target| target.dyn_into().ok())\n    }\n\n    #[inline]\n    /// Performs a zero-cost unchecked cast of this events target into the type `T`.\n    ///\n    /// This method **does not check whether the event target is an instance of `T`**. If used\n    /// incorrectly then this method may cause runtime exceptions in both Rust and JS, this should\n    /// be used with caution.\n    ///\n    /// A common safe usage of this method is within a [`Callback`] that is applied directly to an\n    /// element that has no children, thus `T` will be the type of the element the [`Callback`] is\n    /// applied to.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use web_sys::HtmlInputElement;\n    /// use yew::prelude::*;\n    /// # enum Msg {\n    /// #   Value(String),\n    /// # }\n    /// # struct Comp;\n    /// # impl Component for Comp {\n    /// # type Message = Msg;\n    /// # type Properties = ();\n    /// # fn create(ctx: &Context<Self>) -> Self {\n    /// #   Self\n    /// # }\n    ///\n    /// fn view(&self, ctx: &Context<Self>) -> Html {\n    ///     html! {\n    ///         <input type=\"text\"\n    ///             onchange={ctx.link().callback(|e: Event| {\n    ///                 // Safe to use as callback is on an `input` element so this event can\n    ///                 // only come from this input!\n    ///                 let input: HtmlInputElement = e.target_unchecked_into();\n    ///                 Msg::Value(input.value())\n    ///             })}\n    ///         />\n    ///     }\n    /// }\n    /// # }\n    /// ```\n    fn target_unchecked_into<T>(&self) -> T\n    where\n        T: AsRef<EventTarget> + JsCast,\n    {\n        self.as_ref().target().unwrap().unchecked_into()\n    }\n}\n\nimpl<E: AsRef<Event>> TargetCast for E {}\n\n/// A trait similar to `Into<T>` which allows conversion of a value into a [`Callback`].\n/// This is used for event listeners.\npub trait IntoEventCallback<EVENT> {\n    /// Convert `self` to `Option<Callback<EVENT>>`\n    fn into_event_callback(self) -> Option<Callback<EVENT>>;\n}\n\nimpl<EVENT> IntoEventCallback<EVENT> for Callback<EVENT> {\n    fn into_event_callback(self) -> Option<Callback<EVENT>> {\n        Some(self)\n    }\n}\n\nimpl<EVENT> IntoEventCallback<EVENT> for &Callback<EVENT> {\n    fn into_event_callback(self) -> Option<Callback<EVENT>> {\n        Some(self.clone())\n    }\n}\n\nimpl<EVENT> IntoEventCallback<EVENT> for Option<Callback<EVENT>> {\n    fn into_event_callback(self) -> Option<Callback<EVENT>> {\n        self\n    }\n}\n\nimpl<T, EVENT> IntoEventCallback<EVENT> for T\nwhere\n    T: Fn(EVENT) + 'static,\n{\n    fn into_event_callback(self) -> Option<Callback<EVENT>> {\n        Some(Callback::from(self))\n    }\n}\n\nimpl<T, EVENT> IntoEventCallback<EVENT> for Option<T>\nwhere\n    T: Fn(EVENT) + 'static,\n{\n    fn into_event_callback(self) -> Option<Callback<EVENT>> {\n        Some(Callback::from(self?))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn supported_into_event_callback_types() {\n        let f = |_: usize| ();\n        let cb = Callback::from(f);\n\n        // Callbacks\n        let _: Option<Callback<usize>> = cb.clone().into_event_callback();\n        let _: Option<Callback<usize>> = (&cb).into_event_callback();\n        let _: Option<Callback<usize>> = Some(cb).into_event_callback();\n\n        // Fns\n        let _: Option<Callback<usize>> = f.into_event_callback();\n        let _: Option<Callback<usize>> = Some(f).into_event_callback();\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/html/mod.rs",
    "content": "//! The main html module which defines components, listeners, and class helpers.\n\nmod classes;\nmod component;\nmod conversion;\nmod error;\nmod listener;\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\npub use classes::*;\npub use component::*;\npub use conversion::*;\npub use error::*;\npub use listener::*;\nuse wasm_bindgen::JsValue;\nuse web_sys::{Element, Node};\n\nuse crate::sealed::Sealed;\nuse crate::virtual_dom::{VNode, VPortal};\n\n/// A type which expected as a result of `view` function implementation.\npub type Html = VNode;\n\n/// An enhanced type of `Html` returned in suspendible function components.\npub type HtmlResult = RenderResult<Html>;\n\nimpl Sealed for HtmlResult {}\nimpl Sealed for Html {}\n\n/// A trait to translate into a [`HtmlResult`].\npub trait IntoHtmlResult: Sealed {\n    /// Performs the conversion.\n    fn into_html_result(self) -> HtmlResult;\n}\n\nimpl IntoHtmlResult for HtmlResult {\n    #[inline(always)]\n    fn into_html_result(self) -> HtmlResult {\n        self\n    }\n}\nimpl IntoHtmlResult for Html {\n    #[inline(always)]\n    fn into_html_result(self) -> HtmlResult {\n        Ok(self)\n    }\n}\n\n/// Wrapped Node reference for later use in Component lifecycle methods.\n///\n/// # Example\n/// Focus an `<input>` element on mount.\n/// ```\n/// use web_sys::HtmlInputElement;\n/// # use yew::prelude::*;\n///\n/// pub struct Input {\n///     node_ref: NodeRef,\n/// }\n///\n/// impl Component for Input {\n///     type Message = ();\n///     type Properties = ();\n///\n///     fn create(_ctx: &Context<Self>) -> Self {\n///         Input {\n///             node_ref: NodeRef::default(),\n///         }\n///     }\n///\n///     fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n///         if first_render {\n///             if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n///                 input.focus();\n///             }\n///         }\n///     }\n///\n///     fn view(&self, _ctx: &Context<Self>) -> Html {\n///         html! {\n///             <input ref={self.node_ref.clone()} type=\"text\" />\n///         }\n///     }\n/// }\n/// ```\n/// ## Relevant examples\n/// - [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n#[derive(Default, Clone, ImplicitClone)]\npub struct NodeRef(Rc<RefCell<NodeRefInner>>);\n\nimpl PartialEq for NodeRef {\n    fn eq(&self, other: &Self) -> bool {\n        std::ptr::eq(self.0.as_ptr(), other.0.as_ptr())\n    }\n}\n\nimpl std::fmt::Debug for NodeRef {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"NodeRef {{ references: {:?} }}\",\n            self.get().map(|n| crate::utils::print_node(&n))\n        )\n    }\n}\n\n#[derive(PartialEq, Debug, Default, Clone)]\nstruct NodeRefInner {\n    node: Option<Node>,\n}\n\nimpl NodeRef {\n    /// Get the wrapped Node reference if it exists\n    pub fn get(&self) -> Option<Node> {\n        let inner = self.0.borrow();\n        inner.node.clone()\n    }\n\n    /// Try converting the node reference into another form\n    pub fn cast<INTO: AsRef<Node> + From<JsValue>>(&self) -> Option<INTO> {\n        let node = self.get();\n        node.map(Into::into).map(INTO::from)\n    }\n}\n\n#[cfg(feature = \"csr\")]\nmod feat_csr {\n    use super::*;\n\n    impl NodeRef {\n        pub(crate) fn set(&self, new_ref: Option<Node>) {\n            let mut inner = self.0.borrow_mut();\n            inner.node = new_ref;\n        }\n    }\n}\n\n/// Render children into a DOM node that exists outside the hierarchy of the parent\n/// component.\n/// ## Relevant examples\n/// - [Portals](https://github.com/yewstack/yew/tree/master/examples/portals)\npub fn create_portal(child: Html, host: Element) -> Html {\n    VNode::VPortal(Rc::new(VPortal::new(child, host)))\n}\n"
  },
  {
    "path": "packages/yew/src/lib.rs",
    "content": "#![allow(clippy::needless_doctest_main)]\n#![doc(html_logo_url = \"https://yew.rs/img/logo.png\")]\n#![cfg_attr(documenting, feature(doc_cfg))]\n#![cfg_attr(nightly_yew, feature(fn_traits, unboxed_closures))]\n\n//! # Yew Framework - API Documentation\n//!\n//! Yew is a modern Rust framework for creating multi-threaded front-end web apps using WebAssembly\n//!\n//! - Features a macro for declaring interactive HTML with Rust expressions. Developers who have\n//!   experience using JSX in React should feel quite at home when using Yew.\n//! - Achieves high performance by minimizing DOM API calls for each page render and by making it\n//!   easy to offload processing to background web workers.\n//! - Supports JavaScript interoperability, allowing developers to leverage NPM packages and\n//!   integrate with existing JavaScript applications.\n//!\n//! ### Supported Targets (Client-Side Rendering)\n//! - `wasm32-unknown-unknown`\n//!\n//! ### Note\n//!\n//! Server-Side Rendering should work on all targets when feature `ssr` is enabled.\n//!\n//! ### Supported Features:\n//! - `csr`: Enables Client-side Rendering support and [`Renderer`]. Only enable this feature if you\n//!   are making a Yew application (not a library).\n//! - `ssr`: Enables Server-side Rendering support and [`ServerRenderer`].\n//! - `hydration`: Enables Hydration support.\n//!\n//! ## Example\n//!\n//! ```rust,no_run\n//! use yew::prelude::*;\n//!\n//! enum Msg {\n//!     AddOne,\n//! }\n//!\n//! struct App {\n//!     value: i64,\n//! }\n//!\n//! impl Component for App {\n//!     type Message = Msg;\n//!     type Properties = ();\n//!\n//!     fn create(ctx: &Context<Self>) -> Self {\n//!         Self { value: 0 }\n//!     }\n//!\n//!     fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n//!         match msg {\n//!             Msg::AddOne => {\n//!                 self.value += 1;\n//!                 true\n//!             }\n//!         }\n//!     }\n//!\n//!     fn view(&self, ctx: &Context<Self>) -> Html {\n//!         html! {\n//!             <div>\n//!                 <button onclick={ctx.link().callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n//!                 <p>{ self.value }</p>\n//!             </div>\n//!         }\n//!     }\n//! }\n//!\n//! fn main() {\n//!     yew::Renderer::<App>::new().render();\n//! }\n//! ```\n\n#![deny(\n    missing_docs,\n    missing_debug_implementations,\n    bare_trait_objects,\n    anonymous_parameters,\n    elided_lifetimes_in_paths\n)]\n#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]\n#![recursion_limit = \"512\"]\nextern crate self as yew;\n\n/// This macro provides a convenient way to create [`Classes`].\n///\n/// The macro takes a list of items similar to the [`vec!`] macro and returns a [`Classes`]\n/// instance. Each item can be of any type that implements `Into<Classes>` (See the\n/// implementations on [`Classes`] to learn what types can be used).\n///\n/// # Example\n///\n/// ```\n/// # use yew::prelude::*;\n/// # fn test() {\n/// let conditional_class = Some(\"my-other-class\");\n/// let vec_of_classes = vec![\n///     \"one-bean\",\n///     \"two-beans\",\n///     \"three-beans\",\n///     \"a-very-small-casserole\",\n/// ];\n///\n/// html! {\n///     <div class={classes!(\"my-container-class\", conditional_class, vec_of_classes)}>\n///         // ...\n///     </div>\n/// };\n/// # }\n/// ```\npub use yew_macro::classes;\n/// This macro implements JSX-like templates.\n///\n/// This macro always returns [`Html`].\n/// If you need to preserve the type of a component, use the [`html_nested!`] macro instead.\n///\n/// More information about using the `html!` macro can be found in the [Yew Docs]\n///\n/// [`Html`]: ./html/type.Html.html\n/// [`html_nested!`]: ./macro.html_nested.html\n/// [Yew Docs]: https://yew.rs/docs/next/concepts/html\npub use yew_macro::html;\n/// This macro is similar to [`html!`], but preserves the component type instead\n/// of wrapping it in [`Html`].\n///\n/// That macro is useful when, for example, in a typical implementation of a list\n/// component (let's assume it's called `List`).\n/// In a typical implementation you might find two component types -- `List` and `ListItem`.\n/// Only `ListItem` components are allowed to be children of List`.\n///\n/// You can find an example implementation of this in the [`nested_list`] example.\n/// That example shows, how to create static lists with their children.\n///\n/// ```\n/// # use yew::prelude::*;\n/// use yew::html::ChildrenRenderer;\n/// use yew::virtual_dom::VChild;\n///\n/// #[derive(Clone, Properties, PartialEq)]\n/// struct ListProps {\n///     children: ChildrenRenderer<ListItem>,\n/// }\n///\n/// struct List;\n/// impl Component for List {\n/// #   type Message = ();\n///     type Properties = ListProps;\n///     // ...\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html { unimplemented!() }\n/// }\n///\n/// #[derive(Clone, PartialEq)]\n/// struct ListItem;\n/// impl Component for ListItem {\n/// #   type Message = ();\n/// #   type Properties = ();\n///     // ...\n/// #   fn create(ctx: &Context<Self>) -> Self { Self }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html { unimplemented!() }\n/// }\n///\n/// // Required for ChildrenRenderer\n/// impl From<VChild<ListItem>> for ListItem {\n///     fn from(child: VChild<ListItem>) -> Self {\n///         Self\n///     }\n/// }\n///\n/// impl Into<Html> for ListItem {\n///     fn into(self) -> Html {\n///         html! { <self /> }\n///     }\n/// }\n/// // You can use `List` with nested `ListItem` components.\n/// // Using any other kind of element would result in a compile error.\n/// # fn test() -> Html {\n/// html! {\n///   <List>\n///     <ListItem/>\n///     <ListItem/>\n///     <ListItem/>\n///   </List>\n/// }\n/// # }\n/// # fn test_iter() -> Html {\n/// # let some_iter = (0..10);\n/// // In many cases you might want to create the content dynamically.\n/// // To do this, you can use the following code:\n/// html! {\n///   <List>\n///     { for some_iter.map(|_| html_nested!{ <ListItem/> }) }\n///   </List>\n/// }\n/// # }\n/// ```\n///\n/// If you used the [`html!`] macro instead of `html_nested!`, the code would\n/// not compile because we explicitly indicated to the compiler that `List`\n/// can only contain elements of type `ListItem` using [`ChildrenRenderer<ListItem>`],\n/// while [`html!`] creates items of type [`Html`].\n///\n///\n/// [`html!`]: ./macro.html.html\n/// [`Html`]: ./html/type.Html.html\n/// [`nested_list`]: https://github.com/yewstack/yew/tree/master/examples/nested_list\n/// [`ChildrenRenderer<ListItem>`]: ./html/struct.ChildrenRenderer.html\npub use yew_macro::html_nested;\n/// Build [`Properties`] outside of the [`html!`] macro.\n///\n/// It's already possible to create properties like normal Rust structs\n/// but if there are lots of optional props the end result is often needlessly verbose.\n/// This macro allows you to build properties the same way the [`html!`] macro does.\n///\n/// The macro doesn't support special props like `ref` and `key`, they need to be set in the\n/// [`html!`] macro.\n///\n/// You can read more about `Properties` in the [Yew Docs].\n///\n/// # Example\n///\n/// ```\n/// # use yew::prelude::*;\n/// use std::borrow::Cow;\n///\n/// #[derive(Clone, Properties, PartialEq)]\n/// struct Props {\n///     #[prop_or_default]\n///     id: usize,\n///     name: Cow<'static, str>,\n/// }\n///\n/// struct MyComponent(Props);\n/// impl Component for MyComponent {\n/// #   type Message = ();\n///     type Properties = Props;\n///     // ...\n/// #   fn create(ctx: &Context<Self>) -> Self { unimplemented!() }\n/// #   fn view(&self, ctx: &Context<Self>) -> Html { unimplemented!() }\n/// }\n///\n/// # fn foo() -> Html {\n/// // You can build props directly ...\n/// let props = yew::props!(Props {\n///     name: Cow::from(\"Minka\")\n/// });\n/// # assert_eq!(props.name, \"Minka\");\n/// // ... or build the associated properties of a component\n/// let props = yew::props!(MyComponent::Properties {\n///     id: 2,\n///     name: Cow::from(\"Lemmy\")\n/// });\n/// # assert_eq!(props.id, 2);\n///\n/// // Use the Rust-like struct update syntax to create a component with the props.\n/// html! {\n///     <MyComponent key=1 ..props />\n/// }\n/// # }\n/// ```\n///\n/// [`html!`]: ./macro.html.html\n/// [`Properties`]: ./html/trait.Properties.html\n/// [Yew Docs]: https://yew.rs/concepts/components/properties\npub use yew_macro::props;\n\n/// This module contains macros which implements html! macro and JSX-like templates\npub mod macros {\n    pub use crate::{classes, html, html_nested, props};\n}\n\npub mod callback;\npub mod context;\n#[cfg(feature = \"csr\")]\nmod dom_bundle;\npub mod functional;\npub mod html;\npub mod platform;\npub mod scheduler;\nmod sealed;\n#[cfg(feature = \"ssr\")]\nmod server_renderer;\npub mod suspense;\npub mod utils;\npub mod virtual_dom;\n#[cfg(feature = \"ssr\")]\npub use server_renderer::*;\n\n#[cfg(feature = \"csr\")]\nmod app_handle;\n#[cfg(feature = \"csr\")]\nmod renderer;\n\n#[cfg(all(feature = \"csr\", any(test, feature = \"test\")))]\n#[allow(missing_docs)]\npub mod tests;\n\n/// The module that contains all events available in the framework.\npub mod events {\n    #[doc(no_inline)]\n    pub use web_sys::{\n        AnimationEvent, DragEvent, ErrorEvent, Event, FocusEvent, InputEvent, KeyboardEvent,\n        MouseEvent, PointerEvent, ProgressEvent, SubmitEvent, TouchEvent, TransitionEvent, UiEvent,\n        WheelEvent,\n    };\n\n    #[cfg(feature = \"csr\")]\n    pub use crate::dom_bundle::set_event_bubbling;\n    pub use crate::html::TargetCast;\n}\n\n#[cfg(feature = \"csr\")]\npub use crate::app_handle::AppHandle;\n#[cfg(feature = \"csr\")]\npub use crate::renderer::{set_custom_panic_hook, Renderer};\n\npub mod prelude {\n    //! The Yew Prelude\n    //!\n    //! The purpose of this module is to alleviate imports of many common types:\n    //!\n    //! ```\n    //! # #![allow(unused_imports)]\n    //! use yew::prelude::*;\n    //! ```\n\n    #[cfg(feature = \"csr\")]\n    pub use crate::app_handle::AppHandle;\n    pub use crate::callback::{Callback, CallbackRef, CallbackRefMut};\n    pub use crate::context::{ContextHandle, ContextProvider};\n    pub use crate::events::*;\n    pub use crate::functional::*;\n    pub use crate::html::{\n        create_portal, BaseComponent, Children, ChildrenWithProps, Classes, Component, Context,\n        Html, HtmlResult, NodeRef, Properties,\n    };\n    pub use crate::macros::{classes, html, html_nested};\n    pub use crate::suspense::Suspense;\n    pub use crate::virtual_dom::AttrValue;\n}\n\npub use self::prelude::*;\n"
  },
  {
    "path": "packages/yew/src/platform.rs",
    "content": "//! Yew's compatibility between JavaScript Runtime and Native Runtimes.\n//!\n//! This module is also published under the name [tokise] on crates.io.\n//!\n//! # Rationale\n//!\n//! When designing components and libraries that works on both WebAssembly targets backed by\n//! JavaScript Runtime and non-WebAssembly targets with Native Runtimes. Developers usually face\n//! challenges that requires applying multiple feature flags throughout their application:\n//!\n//! 1. Select I/O and timers that works with the target runtime.\n//! 2. Native Runtimes usually require `Send` futures and WebAssembly types are usually `!Send`.\n//!\n//! # Implementation\n//!\n//! To alleviate these issues, Yew implements a single-threaded runtime that executes `?Send`\n//! (`Send` or `!Send`) futures.\n//!\n//! On platforms with multi-threading support, Yew spawns multiple independent runtimes\n//! proportional to the CPU core number. When tasks are spawned with a runtime handle, it will\n//! randomly select a worker thread from the internal pool. All tasks spawned with `spawn_local`\n//! will run on the same thread as the thread the task was running. When the runtime runs in a\n//! WebAssembly target, all tasks will be scheduled on the main thread.\n//!\n//! This runtime is designed in favour of IO-bounded workload with similar runtime cost.\n//! When running I/O workloads, it would produce a slightly better performance as tasks are\n//! never moved to another thread. However, If a worker thread is busy,\n//! other threads will not be able to steal tasks scheduled on the busy thread.\n//! When you have a CPU-bounded task where CPU time is significantly\n//! more expensive, it should be spawned with a dedicated thread (or Web Worker) and communicates\n//! with the application using channels.\n//!\n//! Yew platform provides the following components:\n//!\n//! 1. A Task Scheduler that is capable of running non-Send tasks.\n//! 2. A Timer that is compatible with the scheduler backend.\n//! 3. Task Synchronisation Mechanisms.\n//!\n//! # Runtime Backend\n//!\n//! The Yew runtime is implemented with different runtimes depending on the target platform and can\n//! use all features (timers / IO / task synchronisation) from the selected native runtime:\n//!\n//! - `wasm-bindgen-futures` (WebAssembly targets)\n//! - `tokio` (non-WebAssembly targets)\n\n#[doc(inline)]\npub use tokise::*;\n"
  },
  {
    "path": "packages/yew/src/renderer.rs",
    "content": "use std::cell::Cell;\nuse std::panic::PanicHookInfo as PanicInfo;\nuse std::rc::Rc;\n\nuse web_sys::Element;\n\nuse crate::app_handle::AppHandle;\nuse crate::html::BaseComponent;\n\nthread_local! {\n    static PANIC_HOOK_IS_SET: Cell<bool> = const { Cell::new(false) };\n}\n\n/// Set a custom panic hook.\n/// Unless a panic hook is set through this function, Yew will\n/// overwrite any existing panic hook when an application is rendered with [Renderer].\n#[cfg(feature = \"csr\")]\n#[allow(clippy::incompatible_msrv)]\npub fn set_custom_panic_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + Sync + Send + 'static>) {\n    std::panic::set_hook(hook);\n    PANIC_HOOK_IS_SET.with(|hook_is_set| hook_is_set.set(true));\n}\n\nfn set_default_panic_hook() {\n    if std::thread::panicking() {\n        // very unlikely, but avoid hitting this when running parallel tests.\n        return;\n    }\n    if !PANIC_HOOK_IS_SET.with(|hook_is_set| hook_is_set.replace(true)) {\n        std::panic::set_hook(Box::new(console_error_panic_hook::hook));\n    }\n}\n\n/// The Yew Renderer.\n///\n/// This is the main entry point of a Yew application.\n#[cfg(feature = \"csr\")]\n#[derive(Debug)]\n#[must_use = \"Renderer does nothing unless render() is called.\"]\npub struct Renderer<COMP>\nwhere\n    COMP: BaseComponent + 'static,\n{\n    root: Element,\n    props: COMP::Properties,\n}\n\nimpl<COMP> Default for Renderer<COMP>\nwhere\n    COMP: BaseComponent + 'static,\n    COMP::Properties: Default,\n{\n    fn default() -> Self {\n        Self::with_props(Default::default())\n    }\n}\n\nimpl<COMP> Renderer<COMP>\nwhere\n    COMP: BaseComponent + 'static,\n    COMP::Properties: Default,\n{\n    /// Creates a [Renderer] that renders into the document body with default properties.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Creates a [Renderer] that renders into a custom root with default properties.\n    pub fn with_root(root: Element) -> Self {\n        Self::with_root_and_props(root, Default::default())\n    }\n}\n\nimpl<COMP> Renderer<COMP>\nwhere\n    COMP: BaseComponent + 'static,\n{\n    /// Creates a [Renderer] that renders into the document body with custom properties.\n    pub fn with_props(props: COMP::Properties) -> Self {\n        Self::with_root_and_props(\n            gloo::utils::document()\n                .body()\n                .expect(\"no body node found\")\n                .into(),\n            props,\n        )\n    }\n\n    /// Creates a [Renderer] that renders into a custom root with custom properties.\n    pub fn with_root_and_props(root: Element, props: COMP::Properties) -> Self {\n        Self { root, props }\n    }\n\n    /// Renders the application.\n    pub fn render(self) -> AppHandle<COMP> {\n        set_default_panic_hook();\n        AppHandle::<COMP>::mount_with_props(self.root, Rc::new(self.props))\n    }\n}\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n\n    impl<COMP> Renderer<COMP>\n    where\n        COMP: BaseComponent + 'static,\n    {\n        /// Hydrates the application.\n        pub fn hydrate(self) -> AppHandle<COMP> {\n            set_default_panic_hook();\n            AppHandle::<COMP>::hydrate_with_props(self.root, Rc::new(self.props))\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/scheduler.rs",
    "content": "//! This module contains a scheduler.\n\nuse std::cell::RefCell;\nuse std::collections::BTreeMap;\nuse std::rc::Rc;\n#[cfg(any(test, feature = \"test\"))]\nmod flush_wakers {\n    use std::cell::RefCell;\n    use std::task::Waker;\n\n    thread_local! {\n        static FLUSH_WAKERS: RefCell<Vec<Waker>> = Default::default();\n    }\n\n    #[cfg(all(\n        target_arch = \"wasm32\",\n        not(target_os = \"wasi\"),\n        not(feature = \"not_browser_env\")\n    ))]\n    pub(super) fn register(waker: Waker) {\n        FLUSH_WAKERS.with(|w| {\n            w.borrow_mut().push(waker);\n        });\n    }\n\n    pub(super) fn wake_all() {\n        FLUSH_WAKERS.with(|w| {\n            for waker in w.borrow_mut().drain(..) {\n                waker.wake();\n            }\n        });\n    }\n}\n\n/// Alias for `Rc<RefCell<T>>`\npub type Shared<T> = Rc<RefCell<T>>;\n\n/// A routine which could be run.\npub trait Runnable {\n    /// Runs a routine with a context instance.\n    fn run(self: Box<Self>);\n}\n\nstruct QueueEntry {\n    task: Box<dyn Runnable>,\n}\n\n#[derive(Default)]\nstruct FifoQueue {\n    inner: Vec<QueueEntry>,\n}\n\nimpl FifoQueue {\n    fn push(&mut self, task: Box<dyn Runnable>) {\n        self.inner.push(QueueEntry { task });\n    }\n\n    fn drain_into(&mut self, queue: &mut Vec<QueueEntry>) {\n        queue.append(&mut self.inner);\n    }\n}\n\n#[derive(Default)]\n\nstruct TopologicalQueue {\n    /// The Binary Tree Map guarantees components with lower id (parent) is rendered first\n    inner: BTreeMap<usize, QueueEntry>,\n}\n\nimpl TopologicalQueue {\n    #[cfg(any(feature = \"ssr\", feature = \"csr\"))]\n    fn push(&mut self, component_id: usize, task: Box<dyn Runnable>) {\n        self.inner.insert(component_id, QueueEntry { task });\n    }\n\n    /// Take a single entry, preferring parents over children\n    #[inline]\n    fn pop_topmost(&mut self) -> Option<QueueEntry> {\n        self.inner.pop_first().map(|(_, v)| v)\n    }\n\n    /// Drain all entries, such that children are queued before parents\n    fn drain_post_order_into(&mut self, queue: &mut Vec<QueueEntry>) {\n        if self.inner.is_empty() {\n            return;\n        }\n        let rendered = std::mem::take(&mut self.inner);\n        // Children rendered lifecycle happen before parents.\n        queue.extend(rendered.into_values().rev());\n    }\n}\n\n/// This is a global scheduler suitable to schedule and run any tasks.\n#[derive(Default)]\n#[allow(missing_debug_implementations)] // todo\nstruct Scheduler {\n    // Main queue\n    main: FifoQueue,\n\n    // Component queues\n    destroy: FifoQueue,\n    create: FifoQueue,\n\n    props_update: FifoQueue,\n    update: FifoQueue,\n\n    render: TopologicalQueue,\n    render_first: TopologicalQueue,\n    render_priority: TopologicalQueue,\n\n    rendered_first: TopologicalQueue,\n    rendered: TopologicalQueue,\n}\n\n/// Execute closure with a mutable reference to the scheduler\n#[inline]\nfn with<R>(f: impl FnOnce(&mut Scheduler) -> R) -> R {\n    thread_local! {\n        /// This is a global scheduler suitable to schedule and run any tasks.\n        ///\n        /// Exclusivity of mutable access is controlled by only accessing it through a set of public\n        /// functions.\n        static SCHEDULER: RefCell<Scheduler> = Default::default();\n    }\n\n    SCHEDULER.with(|s| f(&mut s.borrow_mut()))\n}\n\n/// Push a generic [Runnable] to be executed\npub fn push(runnable: Box<dyn Runnable>) {\n    with(|s| s.main.push(runnable));\n    // Execute pending immediately. Necessary for runnables added outside the component lifecycle,\n    // which would otherwise be delayed.\n    start();\n}\n\n#[cfg(any(feature = \"ssr\", feature = \"csr\"))]\nmod feat_csr_ssr {\n    use super::*;\n    /// Push a component creation, first render and first rendered [Runnable]s to be executed\n    pub(crate) fn push_component_create(\n        component_id: usize,\n        create: Box<dyn Runnable>,\n        first_render: Box<dyn Runnable>,\n    ) {\n        with(|s| {\n            s.create.push(create);\n            s.render_first.push(component_id, first_render);\n        });\n    }\n\n    /// Push a component destruction [Runnable] to be executed\n    pub(crate) fn push_component_destroy(runnable: Box<dyn Runnable>) {\n        with(|s| s.destroy.push(runnable));\n    }\n\n    /// Push a component render [Runnable]s to be executed\n    pub(crate) fn push_component_render(component_id: usize, render: Box<dyn Runnable>) {\n        with(|s| {\n            s.render.push(component_id, render);\n        });\n    }\n\n    /// Push a component update [Runnable] to be executed\n    pub(crate) fn push_component_update(runnable: Box<dyn Runnable>) {\n        with(|s| s.update.push(runnable));\n    }\n}\n\n#[cfg(any(feature = \"ssr\", feature = \"csr\"))]\npub(crate) use feat_csr_ssr::*;\n\n#[cfg(feature = \"csr\")]\nmod feat_csr {\n    use super::*;\n\n    pub(crate) fn push_component_rendered(\n        component_id: usize,\n        rendered: Box<dyn Runnable>,\n        first_render: bool,\n    ) {\n        with(|s| {\n            if first_render {\n                s.rendered_first.push(component_id, rendered);\n            } else {\n                s.rendered.push(component_id, rendered);\n            }\n        });\n    }\n\n    pub(crate) fn push_component_props_update(props_update: Box<dyn Runnable>) {\n        with(|s| s.props_update.push(props_update));\n    }\n}\n\n#[cfg(feature = \"csr\")]\npub(crate) use feat_csr::*;\n\n#[cfg(feature = \"hydration\")]\nmod feat_hydration {\n    use super::*;\n\n    pub(crate) fn push_component_priority_render(component_id: usize, render: Box<dyn Runnable>) {\n        with(|s| {\n            s.render_priority.push(component_id, render);\n        });\n    }\n}\n\n#[cfg(feature = \"hydration\")]\npub(crate) use feat_hydration::*;\n\n/// Execute any pending [Runnable]s\npub(crate) fn start_now() {\n    #[tracing::instrument(level = tracing::Level::DEBUG)]\n    fn scheduler_loop() {\n        let mut queue = vec![];\n        loop {\n            with(|s| s.fill_queue(&mut queue));\n            if queue.is_empty() {\n                break;\n            }\n            for r in queue.drain(..) {\n                r.task.run();\n            }\n        }\n    }\n\n    thread_local! {\n        // The lock is used to prevent recursion. If the lock cannot be acquired, it is because the\n        // `start()` method is being called recursively as part of a `runnable.run()`.\n        static LOCK: RefCell<()> = Default::default();\n    }\n\n    LOCK.with(|l| {\n        if let Ok(_lock) = l.try_borrow_mut() {\n            scheduler_loop();\n            #[cfg(any(test, feature = \"test\"))]\n            flush_wakers::wake_all();\n        }\n    });\n}\n\n#[cfg(all(\n    target_arch = \"wasm32\",\n    not(target_os = \"wasi\"),\n    not(feature = \"not_browser_env\")\n))]\nmod arch {\n    use std::sync::atomic::{AtomicBool, Ordering};\n\n    use wasm_bindgen::prelude::*;\n\n    use crate::platform::spawn_local;\n\n    // Really only used as a `Cell<bool>` that is also `Sync`\n    static IS_SCHEDULED: AtomicBool = AtomicBool::new(false);\n    fn check_scheduled() -> bool {\n        // Since we can tolerate starting too many times, and we don't need to \"see\" any stores\n        // done in the scheduler, Relaxed ordering is fine\n        IS_SCHEDULED.load(Ordering::Relaxed)\n    }\n    fn set_scheduled(is: bool) {\n        // See comment in check_scheduled why Relaxed ordering is fine\n        IS_SCHEDULED.store(is, Ordering::Relaxed)\n    }\n\n    #[cfg(any(test, feature = \"test\"))]\n    pub(super) fn is_scheduled() -> bool {\n        check_scheduled()\n    }\n\n    const YIELD_DEADLINE_MS: f64 = 16.0;\n\n    #[wasm_bindgen]\n    extern \"C\" {\n        #[wasm_bindgen(js_name = setTimeout)]\n        fn set_timeout(handler: &js_sys::Function, timeout: i32) -> i32;\n    }\n\n    fn run_scheduler(mut queue: Vec<super::QueueEntry>) {\n        let deadline = js_sys::Date::now() + YIELD_DEADLINE_MS;\n\n        loop {\n            super::with(|s| s.fill_queue(&mut queue));\n            if queue.is_empty() {\n                break;\n            }\n            for r in queue.drain(..) {\n                r.task.run();\n            }\n            if js_sys::Date::now() >= deadline {\n                // Only yield when no DOM-mutating work is pending, so event\n                // handlers that fire during the yield see a consistent DOM.\n                let can_yield = super::with(|s| s.can_yield());\n                if can_yield {\n                    let cb = Closure::once_into_js(move || run_scheduler(queue));\n                    set_timeout(cb.unchecked_ref(), 0);\n                    return;\n                }\n            }\n        }\n\n        set_scheduled(false);\n        #[cfg(any(test, feature = \"test\"))]\n        super::flush_wakers::wake_all();\n    }\n\n    /// We delay the start of the scheduler to the end of the micro task queue.\n    /// So any messages that needs to be queued can be queued.\n    /// Once running, we yield to the browser every ~16ms, but only at points\n    /// where the DOM is in a consistent state (no pending renders/destroys).\n    pub(crate) fn start() {\n        if check_scheduled() {\n            return;\n        }\n        set_scheduled(true);\n        spawn_local(async {\n            run_scheduler(vec![]);\n        });\n    }\n}\n\n#[cfg(any(\n    not(target_arch = \"wasm32\"),\n    target_os = \"wasi\",\n    feature = \"not_browser_env\"\n))]\nmod arch {\n    // Delayed rendering is not very useful in the context of server-side rendering.\n    // There are no event listeners or other high priority events that need to be\n    // processed and we risk of having a future un-finished.\n    // Until scheduler is future-capable which means we can join inside a future,\n    // it can remain synchronous.\n    pub(crate) fn start() {\n        super::start_now();\n    }\n}\n\npub(crate) use arch::*;\n\n/// Flush all pending scheduler work, ensuring all rendering and lifecycle callbacks complete.\n///\n/// On browser WebAssembly targets, the scheduler defers its work to the microtask queue.\n/// This function registers a waker that is notified when `start_now()` finishes draining all\n/// queues, providing proper event-driven render-complete notification without arbitrary sleeps.\n///\n/// On non-browser targets, the scheduler runs synchronously so this simply drains pending work.\n///\n/// Use this in tests after mounting or updating a component to ensure all rendering has\n/// completed before making assertions.\n#[cfg(all(\n    any(test, feature = \"test\"),\n    target_arch = \"wasm32\",\n    not(target_os = \"wasi\"),\n    not(feature = \"not_browser_env\")\n))]\npub async fn flush() {\n    std::future::poll_fn(|cx| {\n        start_now();\n\n        if arch::is_scheduled() {\n            flush_wakers::register(cx.waker().clone());\n            std::task::Poll::Pending\n        } else {\n            std::task::Poll::Ready(())\n        }\n    })\n    .await\n}\n\n/// Flush all pending scheduler work, ensuring all rendering and lifecycle callbacks complete.\n///\n/// On non-browser targets, the scheduler runs synchronously so this simply drains pending work.\n#[cfg(all(\n    any(test, feature = \"test\"),\n    not(all(\n        target_arch = \"wasm32\",\n        not(target_os = \"wasi\"),\n        not(feature = \"not_browser_env\")\n    ))\n))]\npub async fn flush() {\n    start_now();\n}\n\nimpl Scheduler {\n    /// Returns true when no DOM-mutating work is pending, meaning it's safe to\n    /// yield to the browser without leaving the DOM in an inconsistent state.\n    #[cfg(all(\n        target_arch = \"wasm32\",\n        not(target_os = \"wasi\"),\n        not(feature = \"not_browser_env\")\n    ))]\n    fn can_yield(&self) -> bool {\n        self.destroy.inner.is_empty()\n            && self.create.inner.is_empty()\n            && self.render_first.inner.is_empty()\n            && self.render.inner.is_empty()\n            && self.render_priority.inner.is_empty()\n    }\n\n    /// Fill vector with tasks to be executed according to Runnable type execution priority\n    ///\n    /// This method is optimized for typical usage, where possible, but does not break on\n    /// non-typical usage (like scheduling renders in [crate::Component::create()] or\n    /// [crate::Component::rendered()] calls).\n    fn fill_queue(&mut self, to_run: &mut Vec<QueueEntry>) {\n        // Placed first to avoid as much needless work as possible, handling all the other events.\n        // Drained completely, because they are the highest priority events anyway.\n        self.destroy.drain_into(to_run);\n\n        // Create events can be batched, as they are typically just for object creation\n        self.create.drain_into(to_run);\n\n        // These typically do nothing and don't spawn any other events - can be batched.\n        // Should be run only after all first renders have finished.\n        if !to_run.is_empty() {\n            return;\n        }\n\n        // First render must never be skipped and takes priority over main, because it may need\n        // to init `NodeRef`s\n        //\n        // Should be processed one at time, because they can spawn more create and rendered events\n        // for their children.\n        if let Some(r) = self.render_first.pop_topmost() {\n            to_run.push(r);\n            return;\n        }\n\n        self.props_update.drain_into(to_run);\n\n        // Priority rendering\n        //\n        // This is needed for hydration subsequent render to fix node refs.\n        if let Some(r) = self.render_priority.pop_topmost() {\n            to_run.push(r);\n            return;\n        }\n\n        // Children rendered lifecycle happen before parents.\n        self.rendered_first.drain_post_order_into(to_run);\n\n        // Updates are after the first render to ensure we always have the entire child tree\n        // rendered, once an update is processed.\n        //\n        // Can be batched, as they can cause only non-first renders.\n        self.update.drain_into(to_run);\n\n        // Likely to cause duplicate renders via component updates, so placed before them\n        self.main.drain_into(to_run);\n\n        // Run after all possible updates to avoid duplicate renders.\n        //\n        // Should be processed one at time, because they can spawn more create and first render\n        // events for their children.\n        if !to_run.is_empty() {\n            return;\n        }\n\n        // Should be processed one at time, because they can spawn more create and rendered events\n        // for their children.\n        if let Some(r) = self.render.pop_topmost() {\n            to_run.push(r);\n            return;\n        }\n        // These typically do nothing and don't spawn any other events - can be batched.\n        // Should be run only after all renders have finished.\n        // Children rendered lifecycle happen before parents.\n        self.rendered.drain_post_order_into(to_run);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn push_executes_runnables_immediately() {\n        use std::cell::Cell;\n\n        thread_local! {\n            static FLAG: Cell<bool> = Default::default();\n        }\n\n        struct Test;\n        impl Runnable for Test {\n            fn run(self: Box<Self>) {\n                FLAG.with(|v| v.set(true));\n            }\n        }\n\n        push(Box::new(Test));\n        FLAG.with(|v| assert!(v.get()));\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/sealed.rs",
    "content": "/// Base traits for sealed traits.\npub trait Sealed {}\n"
  },
  {
    "path": "packages/yew/src/server_renderer.rs",
    "content": "use std::fmt;\nuse std::future::Future;\n\nuse futures::pin_mut;\nuse futures::stream::{Stream, StreamExt};\nuse tracing::Instrument;\n\nuse crate::html::{BaseComponent, Scope};\nuse crate::platform::fmt::BufStream;\nuse crate::platform::{LocalHandle, Runtime};\n\n#[cfg(feature = \"ssr\")]\npub(crate) mod feat_ssr {\n    /// Passed top-down as context for `render_into_stream` functions to know the current innermost\n    /// `VTag` kind to apply appropriate text escaping.\n    /// Right now this is used to make `VText` nodes aware of their environment and correctly\n    /// escape their contents when rendering them during SSR.\n    #[derive(Default, Clone, Copy)]\n    pub(crate) enum VTagKind {\n        /// <style> tag\n        Style,\n        /// <script> tag\n        Script,\n        #[default]\n        /// any other tag\n        Other,\n    }\n\n    impl<T: AsRef<str>> From<T> for VTagKind {\n        fn from(value: T) -> Self {\n            let value = value.as_ref();\n            if value.eq_ignore_ascii_case(\"style\") {\n                Self::Style\n            } else if value.eq_ignore_ascii_case(\"script\") {\n                Self::Script\n            } else {\n                Self::Other\n            }\n        }\n    }\n}\n\n/// A Yew Server-side Renderer that renders on the current thread.\n///\n/// # Note\n///\n/// This renderer does not spawn its own runtime and can only be used when:\n///\n/// - `wasm-bindgen-futures` is selected as the backend of Yew runtime.\n/// - running within a [`Runtime`](crate::platform::Runtime).\n/// - running within a tokio [`LocalSet`](struct@tokio::task::LocalSet).\n#[cfg(feature = \"ssr\")]\n#[derive(Debug)]\npub struct LocalServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    props: COMP::Properties,\n    hydratable: bool,\n}\n\nimpl<COMP> Default for LocalServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n    COMP::Properties: Default,\n{\n    fn default() -> Self {\n        Self::with_props(COMP::Properties::default())\n    }\n}\n\nimpl<COMP> LocalServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n    COMP::Properties: Default,\n{\n    /// Creates a [LocalServerRenderer] with default properties.\n    pub fn new() -> Self {\n        Self::default()\n    }\n}\n\nimpl<COMP> LocalServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    /// Creates a [LocalServerRenderer] with custom properties.\n    pub fn with_props(props: COMP::Properties) -> Self {\n        Self {\n            props,\n            hydratable: true,\n        }\n    }\n\n    /// Sets whether an the rendered result is hydratable.\n    ///\n    /// Defaults to `true`.\n    ///\n    /// When this is sets to `true`, the rendered artifact will include additional information\n    /// to assist with the hydration process.\n    pub fn hydratable(mut self, val: bool) -> Self {\n        self.hydratable = val;\n\n        self\n    }\n\n    /// Renders Yew Application.\n    pub async fn render(self) -> String {\n        let s = self.render_stream();\n        futures::pin_mut!(s);\n\n        s.collect().await\n    }\n\n    /// Renders Yew Application to a String.\n    pub async fn render_to_string(self, w: &mut String) {\n        let s = self.render_stream();\n        futures::pin_mut!(s);\n\n        while let Some(m) = s.next().await {\n            w.push_str(&m);\n        }\n    }\n\n    fn render_stream_inner(self) -> impl Stream<Item = String> {\n        let scope = Scope::<COMP>::new(None);\n\n        let outer_span = tracing::Span::current();\n        BufStream::new(move |mut w| async move {\n            let render_span = tracing::debug_span!(\"render_stream_item\");\n            render_span.follows_from(outer_span);\n            scope\n                .render_into_stream(\n                    &mut w,\n                    self.props.into(),\n                    self.hydratable,\n                    Default::default(),\n                )\n                .instrument(render_span)\n                .await;\n        })\n    }\n\n    // The duplicate implementation below is to selectively suppress clippy lints.\n    // These implementations should be merged once https://github.com/tokio-rs/tracing/issues/2503 is resolved.\n\n    /// Renders Yew Application into a string Stream\n    #[allow(clippy::let_with_type_underscore)]\n    #[tracing::instrument(\n        level = tracing::Level::DEBUG,\n        name = \"render_stream\",\n        skip(self),\n        fields(hydratable = self.hydratable),\n    )]\n    #[inline(always)]\n    pub fn render_stream(self) -> impl Stream<Item = String> {\n        self.render_stream_inner()\n    }\n}\n\n/// A Yew Server-side Renderer.\n///\n/// This renderer spawns the rendering task to a Yew [`Runtime`]. and receives result when\n/// the rendering process has finished.\n///\n/// See [`yew::platform`] for more information.\n#[cfg(feature = \"ssr\")]\npub struct ServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    create_props: Box<dyn Send + FnOnce() -> COMP::Properties>,\n    hydratable: bool,\n    rt: Option<Runtime>,\n}\n\nimpl<COMP> fmt::Debug for ServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"ServerRenderer<_>\")\n    }\n}\n\nimpl<COMP> Default for ServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n    COMP::Properties: Default,\n{\n    fn default() -> Self {\n        Self::with_props(Default::default)\n    }\n}\n\nimpl<COMP> ServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n    COMP::Properties: Default,\n{\n    /// Creates a [ServerRenderer] with default properties.\n    pub fn new() -> Self {\n        Self::default()\n    }\n}\n\nimpl<COMP> ServerRenderer<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    /// Creates a [ServerRenderer] with custom properties.\n    ///\n    /// # Note\n    ///\n    /// The properties does not have to implement `Send`.\n    /// However, the function to create properties needs to be `Send`.\n    pub fn with_props<F>(create_props: F) -> Self\n    where\n        F: 'static + Send + FnOnce() -> COMP::Properties,\n    {\n        Self {\n            create_props: Box::new(create_props),\n            hydratable: true,\n            rt: None,\n        }\n    }\n\n    /// Sets the runtime the ServerRenderer will run the rendering task with.\n    pub fn with_runtime(mut self, rt: Runtime) -> Self {\n        self.rt = Some(rt);\n\n        self\n    }\n\n    /// Sets whether an the rendered result is hydratable.\n    ///\n    /// Defaults to `true`.\n    ///\n    /// When this is sets to `true`, the rendered artifact will include additional information\n    /// to assist with the hydration process.\n    pub fn hydratable(mut self, val: bool) -> Self {\n        self.hydratable = val;\n\n        self\n    }\n\n    /// Renders Yew Application.\n    pub async fn render(self) -> String {\n        let Self {\n            create_props,\n            hydratable,\n            rt,\n        } = self;\n\n        let (tx, rx) = futures::channel::oneshot::channel();\n        let create_task = move || async move {\n            let props = create_props();\n            let s = LocalServerRenderer::<COMP>::with_props(props)\n                .hydratable(hydratable)\n                .render()\n                .await;\n\n            let _ = tx.send(s);\n        };\n\n        Self::spawn_rendering_task(rt, create_task);\n\n        rx.await.expect(\"failed to render application\")\n    }\n\n    /// Renders Yew Application to a String.\n    pub async fn render_to_string(self, w: &mut String) {\n        let mut s = self.render_stream();\n\n        while let Some(m) = s.next().await {\n            w.push_str(&m);\n        }\n    }\n\n    #[inline]\n    fn spawn_rendering_task<F, Fut>(rt: Option<Runtime>, create_task: F)\n    where\n        F: 'static + Send + FnOnce() -> Fut,\n        Fut: Future<Output = ()> + 'static,\n    {\n        match rt {\n            // If a runtime is specified, spawn to the specified runtime.\n            Some(m) => m.spawn_pinned(create_task),\n            None => match LocalHandle::try_current() {\n                // If within a Yew Runtime, spawn to the current runtime.\n                Some(m) => m.spawn_local(create_task()),\n                // Outside of Yew Runtime, spawn to the default runtime.\n                None => Runtime::default().spawn_pinned(create_task),\n            },\n        }\n    }\n\n    /// Renders Yew Application into a string Stream.\n    pub fn render_stream(self) -> impl Send + Stream<Item = String> {\n        let Self {\n            create_props,\n            hydratable,\n            rt,\n        } = self;\n\n        let (tx, rx) = futures::channel::mpsc::unbounded();\n        let create_task = move || async move {\n            let props = create_props();\n            let s = LocalServerRenderer::<COMP>::with_props(props)\n                .hydratable(hydratable)\n                .render_stream();\n            pin_mut!(s);\n\n            while let Some(m) = s.next().await {\n                let _ = tx.unbounded_send(m);\n            }\n        };\n\n        Self::spawn_rendering_task(rt, create_task);\n\n        rx\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/suspense/component.rs",
    "content": "use crate::html::{Html, Properties};\n\n/// Properties for [Suspense].\n#[derive(Properties, PartialEq, Debug, Clone)]\npub struct SuspenseProps {\n    /// The Children of the current Suspense Component.\n    #[prop_or_default]\n    pub children: Html,\n\n    /// The Fallback UI of the current Suspense Component.\n    #[prop_or_default]\n    pub fallback: Html,\n}\n\n#[cfg(any(feature = \"csr\", feature = \"ssr\"))]\nmod feat_csr_ssr {\n    use super::*;\n    use crate::html::{Component, Context, Html, Scope};\n    use crate::suspense::Suspension;\n    #[cfg(feature = \"hydration\")]\n    use crate::suspense::SuspensionHandle;\n    use crate::virtual_dom::{VNode, VSuspense};\n    use crate::{component, html};\n\n    #[derive(Properties, PartialEq, Debug, Clone)]\n    pub(crate) struct BaseSuspenseProps {\n        pub children: Html,\n        #[prop_or(None)]\n        pub fallback: Option<Html>,\n    }\n\n    #[derive(Debug)]\n    pub(crate) enum BaseSuspenseMsg {\n        Suspend(Suspension),\n        Resume(Suspension),\n    }\n\n    #[derive(Debug)]\n    pub(crate) struct BaseSuspense {\n        suspensions: Vec<Suspension>,\n        #[cfg(feature = \"hydration\")]\n        hydration_handle: Option<SuspensionHandle>,\n    }\n\n    impl Component for BaseSuspense {\n        type Message = BaseSuspenseMsg;\n        type Properties = BaseSuspenseProps;\n\n        fn create(_ctx: &Context<Self>) -> Self {\n            #[cfg(not(feature = \"hydration\"))]\n            let suspensions = Vec::new();\n\n            // We create a suspension to block suspense until its rendered method is notified.\n            #[cfg(feature = \"hydration\")]\n            let (suspensions, hydration_handle) = {\n                use crate::callback::Callback;\n                use crate::html::RenderMode;\n\n                match _ctx.creation_mode() {\n                    RenderMode::Hydration => {\n                        let link = _ctx.link().clone();\n                        let (s, handle) = Suspension::new();\n                        s.listen(Callback::from(move |s| {\n                            link.send_message(BaseSuspenseMsg::Resume(s));\n                        }));\n                        (vec![s], Some(handle))\n                    }\n                    _ => (Vec::new(), None),\n                }\n            };\n\n            Self {\n                suspensions,\n                #[cfg(feature = \"hydration\")]\n                hydration_handle,\n            }\n        }\n\n        fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n            match msg {\n                Self::Message::Suspend(m) => {\n                    assert!(\n                        ctx.props().fallback.is_some(),\n                        \"You cannot suspend from a component rendered as a fallback.\"\n                    );\n\n                    if m.resumed() {\n                        return false;\n                    }\n\n                    // If a suspension already exists, ignore it.\n                    if self.suspensions.iter().any(|n| n == &m) {\n                        return false;\n                    }\n\n                    self.suspensions.push(m);\n\n                    true\n                }\n                Self::Message::Resume(ref m) => {\n                    let suspensions_len = self.suspensions.len();\n                    self.suspensions.retain(|n| m != n);\n\n                    suspensions_len != self.suspensions.len()\n                }\n            }\n        }\n\n        fn view(&self, ctx: &Context<Self>) -> Html {\n            let BaseSuspenseProps { children, fallback } = (*ctx.props()).clone();\n            let children = html! {<>{children}</>};\n\n            match fallback {\n                Some(fallback) => {\n                    let vsuspense = VSuspense::new(\n                        children,\n                        fallback,\n                        !self.suspensions.is_empty(),\n                        // We don't need to key this as the key will be applied to the component.\n                        None,\n                    );\n\n                    VNode::from(vsuspense)\n                }\n                None => children,\n            }\n        }\n\n        #[cfg(feature = \"hydration\")]\n        fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n            if first_render {\n                if let Some(m) = self.hydration_handle.take() {\n                    m.resume();\n                }\n            }\n        }\n    }\n\n    impl BaseSuspense {\n        pub(crate) fn suspend(scope: &Scope<Self>, s: Suspension) {\n            scope.send_message(BaseSuspenseMsg::Suspend(s));\n        }\n\n        pub(crate) fn resume(scope: &Scope<Self>, s: Suspension) {\n            scope.send_message(BaseSuspenseMsg::Resume(s));\n        }\n    }\n\n    /// Suspend rendering and show a fallback UI until the underlying task completes.\n    #[component]\n    pub fn Suspense(props: &SuspenseProps) -> Html {\n        let SuspenseProps { children, fallback } = props.clone();\n\n        let fallback = html! {\n            <BaseSuspense>\n                {fallback}\n            </BaseSuspense>\n        };\n\n        html! {\n            <BaseSuspense {fallback}>\n                {children}\n            </BaseSuspense>\n        }\n    }\n}\n\n#[cfg(any(feature = \"csr\", feature = \"ssr\"))]\npub use feat_csr_ssr::*;\n\n#[cfg(not(any(feature = \"ssr\", feature = \"csr\")))]\nmod feat_no_csr_ssr {\n    use super::*;\n    use crate::component;\n\n    /// Suspend rendering and show a fallback UI until the underlying task completes.\n    #[component]\n    pub fn Suspense(_props: &SuspenseProps) -> Html {\n        Html::default()\n    }\n}\n\n#[cfg(not(any(feature = \"ssr\", feature = \"csr\")))]\npub use feat_no_csr_ssr::*;\n"
  },
  {
    "path": "packages/yew/src/suspense/hooks.rs",
    "content": "use std::cell::Cell;\nuse std::fmt;\nuse std::future::Future;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n/// This hook is used to await a future in a suspending context.\n///\n/// A [Suspension] is created from the passed future and the result of the future\n/// is the output of the suspension.\npub struct UseFutureHandle<O> {\n    inner: UseStateHandle<Option<O>>,\n}\n\nimpl<O> Clone for UseFutureHandle<O> {\n    fn clone(&self) -> Self {\n        Self {\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<O> Deref for UseFutureHandle<O> {\n    type Target = O;\n\n    fn deref(&self) -> &Self::Target {\n        self.inner.as_ref().unwrap()\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for UseFutureHandle<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"UseFutureHandle\")\n            .field(\"value\", &format!(\"{:?}\", self.inner))\n            .finish()\n    }\n}\n\n/// Use the result of an async computation, suspending while waiting.\n///\n/// Awaits the future returned from the first call to `init_f`, and returns\n/// its result in a [`UseFutureHandle`]. Always suspends initially, even if\n/// the future is immediately [ready].\n///\n/// [ready]: std::task::Poll::Ready\n///\n/// # Example\n///\n/// ```\n/// # use yew::prelude::*;\n/// # use yew::suspense::use_future;\n/// use gloo::net::http::Request;\n///\n/// const URL: &str = \"https://en.wikipedia.org/w/api.php?\\\n///                    action=query&origin=*&format=json&generator=search&\\\n///                    gsrnamespace=0&gsrlimit=5&gsrsearch='New_England_Patriots'\";\n///\n/// #[component]\n/// fn WikipediaSearch() -> HtmlResult {\n///     let res = use_future(|| async { Request::get(URL).send().await?.text().await })?;\n///     let result_html = match *res {\n///         Ok(ref res) => html! { res },\n///         Err(ref failure) => failure.to_string().into(),\n///     };\n///     Ok(html! {\n///         <p>\n///             {\"Wikipedia search result: \"}\n///             {result_html}\n///         </p>\n///     })\n/// }\n/// ```\n#[hook]\npub fn use_future<F, T, O>(init_f: F) -> SuspensionResult<UseFutureHandle<O>>\nwhere\n    F: FnOnce() -> T,\n    T: Future<Output = O> + 'static,\n    O: 'static,\n{\n    use_future_with((), move |_| init_f())\n}\n\n/// Use the result of an async computation with dependencies, suspending while waiting.\n///\n/// Awaits the future returned from `f` for the latest `deps`. Even if the future is immediately\n/// [ready], the hook suspends at least once. If the dependencies\n/// change while a future is still pending, the result is never used. This guarantees that your\n/// component always sees up-to-date values while it is not suspended.\n///\n/// [ready]: std::task::Poll::Ready\n#[hook]\npub fn use_future_with<F, D, T, O>(deps: D, f: F) -> SuspensionResult<UseFutureHandle<O>>\nwhere\n    F: FnOnce(Rc<D>) -> T,\n    T: Future<Output = O> + 'static,\n    O: 'static,\n    D: PartialEq + 'static,\n{\n    let output = use_state(|| None);\n    // We only commit a result if it comes from the latest spawned future. Otherwise, this\n    // might trigger pointless updates or even override newer state.\n    let latest_id = use_ref(|| Cell::new(0u32));\n    let suspension = {\n        let output = output.clone();\n\n        use_memo_base(\n            move |deps| {\n                let self_id = latest_id.get().wrapping_add(1);\n                // As long as less than 2**32 futures are in flight wrapping_add is fine\n                (*latest_id).set(self_id);\n                let deps = Rc::new(deps);\n                let task = f(deps.clone());\n                let suspension = Suspension::from_future(async move {\n                    let result = task.await;\n                    if latest_id.get() == self_id {\n                        output.set(Some(result));\n                    }\n                });\n                (suspension, deps)\n            },\n            deps,\n        )\n    };\n\n    if suspension.resumed() {\n        Ok(UseFutureHandle { inner: output })\n    } else {\n        Err((*suspension).clone())\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/suspense/mod.rs",
    "content": "//! This module provides suspense support.\n\nmod component;\nmod hooks;\nmod suspension;\n\n#[cfg(any(feature = \"csr\", feature = \"ssr\"))]\npub(crate) use component::BaseSuspense;\npub use component::{Suspense, SuspenseProps};\npub use hooks::*;\npub use suspension::{Suspension, SuspensionHandle, SuspensionResult};\n"
  },
  {
    "path": "packages/yew/src/suspense/suspension.rs",
    "content": "use std::cell::RefCell;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::rc::Rc;\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse std::task::{Context, Poll};\n\nuse thiserror::Error;\n\nuse crate::platform::spawn_local;\nuse crate::Callback;\n\nthread_local! {\n    static SUSPENSION_ID: RefCell<usize> = RefCell::default();\n}\n\n/// A Suspension.\n///\n/// This type can be sent back as an `Err(_)` to suspend a component until the underlying task\n/// completes.\n#[derive(Error, Debug, Clone)]\n#[error(\"suspend component rendering\")]\npub struct Suspension {\n    id: usize,\n    listeners: Rc<RefCell<Vec<Callback<Self>>>>,\n\n    resumed: Rc<AtomicBool>,\n}\n\nimpl PartialEq for Suspension {\n    fn eq(&self, rhs: &Self) -> bool {\n        self.id == rhs.id\n    }\n}\n\nimpl Suspension {\n    /// Creates a Suspension.\n    pub fn new() -> (Self, SuspensionHandle) {\n        let id = SUSPENSION_ID.with(|m| {\n            let mut m = m.borrow_mut();\n            *m += 1;\n\n            *m\n        });\n\n        let self_ = Suspension {\n            id,\n            listeners: Rc::default(),\n            resumed: Rc::default(),\n        };\n\n        (self_.clone(), SuspensionHandle { inner: self_ })\n    }\n\n    /// Returns `true` if the current suspension is already resumed.\n    pub fn resumed(&self) -> bool {\n        self.resumed.load(Ordering::Relaxed)\n    }\n\n    /// Creates a Suspension that resumes when the [`Future`] resolves.\n    pub fn from_future(f: impl Future<Output = ()> + 'static) -> Self {\n        let (self_, handle) = Self::new();\n\n        spawn_local(async move {\n            f.await;\n            handle.resume();\n        });\n\n        self_\n    }\n\n    /// Listens to a suspension and get notified when it resumes.\n    pub(crate) fn listen(&self, cb: Callback<Self>) {\n        if self.resumed() {\n            cb.emit(self.clone());\n            return;\n        }\n\n        let mut listeners = self.listeners.borrow_mut();\n\n        listeners.push(cb);\n    }\n\n    fn resume_by_ref(&self) {\n        // The component can resume rendering by returning a non-suspended result after a state is\n        // updated, so we always need to check here.\n        if !self.resumed() {\n            self.resumed.store(true, Ordering::Relaxed);\n            let listeners = self.listeners.borrow();\n\n            for listener in listeners.iter() {\n                listener.emit(self.clone());\n            }\n        }\n    }\n}\n\nimpl Future for Suspension {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        if self.resumed() {\n            return Poll::Ready(());\n        }\n\n        let waker = cx.waker().clone();\n        self.listen(Callback::from(move |_| {\n            waker.wake_by_ref();\n        }));\n\n        Poll::Pending\n    }\n}\n\n/// A Suspension Result.\npub type SuspensionResult<T> = std::result::Result<T, Suspension>;\n\n/// A Suspension Handle.\n///\n/// This type is used to control the corresponding [`Suspension`].\n///\n/// When the current struct is dropped or `resume` is called, it will resume rendering of current\n/// component.\n#[derive(Debug, PartialEq)]\npub struct SuspensionHandle {\n    inner: Suspension,\n}\n\nimpl SuspensionHandle {\n    /// Resumes component rendering.\n    pub fn resume(self) {\n        self.inner.resume_by_ref();\n    }\n}\n\nimpl Drop for SuspensionHandle {\n    fn drop(&mut self) {\n        self.inner.resume_by_ref();\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/tests/layout_tests.rs",
    "content": "//! Snapshot testing of Yew components\n//!\n//! This tests must be run in browser and thus require the `csr` feature to be enabled\nuse gloo::console::log;\n\nuse crate::dom_bundle::{BSubtree, Bundle, DomSlot};\nuse crate::html::AnyScope;\nuse crate::virtual_dom::VNode;\nuse crate::{scheduler, Component, Context, Html};\n\n#[allow(dead_code)]\nstruct Comp;\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: &Context<Self>) -> Self {\n        unimplemented!()\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {\n        unimplemented!();\n    }\n\n    fn changed(&mut self, _ctx: &Context<Self>, _: &Self::Properties) -> bool {\n        unimplemented!()\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        unimplemented!()\n    }\n}\n\n#[derive(Debug)]\n#[allow(missing_docs)]\npub struct TestLayout<'a> {\n    pub name: &'a str,\n    pub node: VNode,\n    pub expected: &'a str,\n}\n\n#[allow(missing_docs)]\npub fn diff_layouts(layouts: Vec<TestLayout<'_>>) {\n    let document = gloo::utils::document();\n    let scope: AnyScope = AnyScope::test();\n    let parent_element = document.create_element(\"div\").unwrap();\n    let root = BSubtree::create_root(&parent_element);\n\n    let end_node = document.create_text_node(\"END\");\n    parent_element.append_child(&end_node).unwrap();\n\n    // Tests each layout independently\n    let slot = DomSlot::at(end_node.into());\n    for layout in layouts.iter() {\n        // Apply the layout\n        let vnode = layout.node.clone();\n        log!(\"Independently apply layout '{}'\", layout.name);\n\n        let mut bundle = Bundle::new();\n        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), vnode);\n        scheduler::start_now();\n        assert_eq!(\n            parent_element.inner_html(),\n            format!(\"{}END\", layout.expected),\n            \"Independent apply failed for layout '{}'\",\n            layout.name,\n        );\n\n        // Diff with no changes\n        let vnode = layout.node.clone();\n\n        log!(\"Independently reapply layout '{}'\", layout.name);\n\n        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), vnode);\n        scheduler::start_now();\n        assert_eq!(\n            parent_element.inner_html(),\n            format!(\"{}END\", layout.expected),\n            \"Independent reapply failed for layout '{}'\",\n            layout.name,\n        );\n\n        // Detach\n        bundle.detach(&root, &parent_element, false);\n        scheduler::start_now();\n        assert_eq!(\n            parent_element.inner_html(),\n            \"END\",\n            \"Independent detach failed for layout '{}'\",\n            layout.name,\n        );\n    }\n\n    // Sequentially apply each layout\n    let mut bundle = Bundle::new();\n    for layout in layouts.iter() {\n        let next_vnode = layout.node.clone();\n\n        log!(\"Sequentially apply layout '{}'\", layout.name);\n        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), next_vnode);\n\n        scheduler::start_now();\n        assert_eq!(\n            parent_element.inner_html(),\n            format!(\"{}END\", layout.expected),\n            \"Sequential apply failed for layout '{}'\",\n            layout.name,\n        );\n    }\n\n    // Sequentially detach each layout\n    for layout in layouts.into_iter().rev() {\n        let next_vnode = layout.node.clone();\n\n        log!(\"Sequentially detach layout '{}'\", layout.name);\n        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), next_vnode);\n\n        scheduler::start_now();\n        assert_eq!(\n            parent_element.inner_html(),\n            format!(\"{}END\", layout.expected),\n            \"Sequential detach failed for layout '{}'\",\n            layout.name,\n        );\n    }\n\n    // Detach last layout\n    bundle.detach(&root, &parent_element, false);\n    scheduler::start_now();\n    assert_eq!(\n        parent_element.inner_html(),\n        \"END\",\n        \"Failed to detach last layout\"\n    );\n}\n"
  },
  {
    "path": "packages/yew/src/tests/mod.rs",
    "content": "//! Internal module for unit tests\npub mod layout_tests;\n"
  },
  {
    "path": "packages/yew/src/utils/mod.rs",
    "content": "//! This module contains useful utilities to get information about the current document.\n\nuse std::marker::PhantomData;\nuse std::rc::Rc;\n\nuse implicit_clone::unsync::IArray;\nuse implicit_clone::ImplicitClone;\nuse yew::html::ChildrenRenderer;\n\n/// Map `IntoIterator<Item = Into<T>>` to `Iterator<Item = T>`\npub fn into_node_iter<IT, T, R>(it: IT) -> impl Iterator<Item = R>\nwhere\n    IT: IntoIterator<Item = T>,\n    T: Into<R>,\n{\n    it.into_iter().map(|n| n.into())\n}\n\nfn array_single<T: ImplicitClone + 'static>(single: T) -> IArray<T> {\n    IArray::Rc(Rc::new([single]))\n}\n\n/// A special type necessary for flattening components returned from nested html macros.\n#[derive(Debug)]\npub struct NodeSeq<IN, OUT: ImplicitClone + 'static>(IArray<OUT>, PhantomData<IN>);\n\nimpl<IN: Into<OUT>, OUT: ImplicitClone + 'static> From<IN> for NodeSeq<IN, OUT> {\n    fn from(val: IN) -> Self {\n        Self(array_single(val.into()), PhantomData)\n    }\n}\n\nimpl<IN: Into<OUT>, OUT: ImplicitClone + 'static> From<Option<IN>> for NodeSeq<IN, OUT> {\n    fn from(val: Option<IN>) -> Self {\n        Self(\n            val.map(|s| array_single(s.into())).unwrap_or_default(),\n            PhantomData,\n        )\n    }\n}\n\nimpl<IN: Into<OUT>, OUT: ImplicitClone + 'static> From<Vec<IN>> for NodeSeq<IN, OUT> {\n    fn from(mut val: Vec<IN>) -> Self {\n        if val.len() == 1 {\n            let item = val.pop().unwrap();\n            Self(array_single(item.into()), PhantomData)\n        } else {\n            Self(val.into_iter().map(|x| x.into()).collect(), PhantomData)\n        }\n    }\n}\n\nimpl<IN: Into<OUT> + ImplicitClone, OUT: ImplicitClone + 'static> From<IArray<IN>>\n    for NodeSeq<IN, OUT>\n{\n    fn from(val: IArray<IN>) -> Self {\n        Self(val.into_iter().map(|x| x.into()).collect(), PhantomData)\n    }\n}\n\nimpl<IN: Into<OUT> + ImplicitClone, OUT: ImplicitClone + 'static> From<&IArray<IN>>\n    for NodeSeq<IN, OUT>\n{\n    fn from(val: &IArray<IN>) -> Self {\n        Self(\n            val.clone().into_iter().map(|x| x.into()).collect(),\n            PhantomData,\n        )\n    }\n}\n\nimpl<IN: Into<OUT> + Clone, OUT: ImplicitClone + 'static> From<&ChildrenRenderer<IN>>\n    for NodeSeq<IN, OUT>\n{\n    fn from(val: &ChildrenRenderer<IN>) -> Self {\n        Self(val.iter().map(|x| x.into()).collect(), PhantomData)\n    }\n}\n\nimpl<IN, OUT: ImplicitClone + 'static> IntoIterator for NodeSeq<IN, OUT> {\n    type IntoIter = implicit_clone::unsync::IArrayIntoIter<Self::Item>;\n    type Item = OUT;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.0.into_iter()\n    }\n}\n\n/// Hack to force type mismatch compile errors in yew-macro.\n// TODO: replace with `compile_error!`, when `type_name_of_val` is stabilised (https://github.com/rust-lang/rust/issues/66359).\n#[doc(hidden)]\npub fn __ensure_type<T>(_: T) {}\n\n/// Print the [web_sys::Node]'s contents as a string for debugging purposes\npub fn print_node(n: &web_sys::Node) -> String {\n    use wasm_bindgen::JsCast;\n\n    match n.dyn_ref::<web_sys::Element>() {\n        Some(el) => el.outer_html(),\n        None => n.text_content().unwrap_or_default(),\n    }\n}\n\n// NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable\npub(crate) trait RcExt<T: Clone> {\n    fn unwrap_or_clone(this: Self) -> T;\n}\n\nimpl<T: Clone> RcExt<T> for std::rc::Rc<T> {\n    fn unwrap_or_clone(this: Self) -> T {\n        std::rc::Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone())\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/key.rs",
    "content": "//! This module contains the implementation yew's virtual nodes' keys.\n\nuse std::fmt::{self, Display, Formatter};\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse crate::html::ImplicitClone;\n\n/// Represents the (optional) key of Yew's virtual nodes.\n///\n/// Keys are cheap to clone.\n#[derive(Clone, ImplicitClone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]\npub struct Key {\n    key: Rc<str>,\n}\n\nimpl Display for Key {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        self.key.fmt(f)\n    }\n}\n\nimpl Deref for Key {\n    type Target = str;\n\n    fn deref(&self) -> &str {\n        self.key.as_ref()\n    }\n}\n\nimpl From<Rc<str>> for Key {\n    fn from(key: Rc<str>) -> Self {\n        Self { key }\n    }\n}\n\nimpl From<&'_ str> for Key {\n    fn from(key: &'_ str) -> Self {\n        let key: Rc<str> = Rc::from(key);\n        Self::from(key)\n    }\n}\n\nimpl From<String> for Key {\n    fn from(key: String) -> Self {\n        Self::from(key.as_str())\n    }\n}\n\nmacro_rules! key_impl_from_to_string {\n    ($type:ty) => {\n        impl From<$type> for Key {\n            fn from(key: $type) -> Self {\n                Self::from(key.to_string().as_str())\n            }\n        }\n    };\n}\n\nkey_impl_from_to_string!(char);\nkey_impl_from_to_string!(u8);\nkey_impl_from_to_string!(u16);\nkey_impl_from_to_string!(u32);\nkey_impl_from_to_string!(u64);\nkey_impl_from_to_string!(u128);\nkey_impl_from_to_string!(usize);\nkey_impl_from_to_string!(i8);\nkey_impl_from_to_string!(i16);\nkey_impl_from_to_string!(i32);\nkey_impl_from_to_string!(i64);\nkey_impl_from_to_string!(i128);\nkey_impl_from_to_string!(isize);\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[cfg(test)]\nmod test {\n    use std::rc::Rc;\n\n    use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\n\n    use crate::html;\n\n    wasm_bindgen_test_configure!(run_in_browser);\n\n    #[test]\n    fn all_key_conversions() {\n        let _ = html! {\n            <key=\"string literal\">\n                <img key={\"String\".to_owned()} />\n                <p key={Rc::<str>::from(\"rc\")}></p>\n                <key='a'>\n                    <p key=11_usize></p>\n                    <p key=12_u8></p>\n                    <p key=13_u16></p>\n                    <p key=14_u32></p>\n                    <p key=15_u64></p>\n                    <p key=16_u128></p>\n                    <p key=21_isize></p>\n                    <p key=22_i8></p>\n                    <p key=23_i16></p>\n                    <p key=24_i32></p>\n                    <p key=25_i128></p>\n                </>\n            </>\n        };\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/listeners.rs",
    "content": "use std::rc::Rc;\n\nuse crate::html::ImplicitClone;\n\n/// The [Listener] trait is an universal implementation of an event listener\n/// which is used to bind Rust-listener to JS-listener (DOM).\npub trait Listener {\n    /// Returns the name of the event\n    fn kind(&self) -> ListenerKind;\n\n    /// Handles an event firing\n    fn handle(&self, event: web_sys::Event);\n\n    /// Makes the event listener passive. See\n    /// [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener).\n    fn passive(&self) -> bool;\n}\n\nimpl std::fmt::Debug for dyn Listener {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"Listener {{ kind: {}, passive: {:?} }}\",\n            self.kind().as_ref(),\n            self.passive(),\n        )\n    }\n}\n\nmacro_rules! gen_listener_kinds {\n    ($($kind:ident)*) => {\n        /// Supported kinds of DOM event listeners\n        // Using instead of strings to optimise registry collection performance by simplifying\n        // hashmap hash calculation.\n        #[derive(Clone, PartialEq, Eq, Hash, Debug)]\n        #[allow(non_camel_case_types)]\n        #[allow(missing_docs)]\n        pub enum ListenerKind {\n            $( $kind, )*\n            other(std::borrow::Cow<'static, str>),\n        }\n\n        impl ListenerKind {\n            pub fn type_name(&self) -> std::borrow::Cow<'static, str> {\n                match self {\n                    Self::other(type_name) => type_name.clone(),\n                    $( Self::$kind => stringify!($kind)[2..].into(), )*\n                }\n            }\n        }\n\n        impl AsRef<str> for ListenerKind {\n            fn as_ref(&self) -> &str {\n                match self {\n                    $( Self::$kind => stringify!($kind), )*\n                    Self::other(type_name) => type_name.as_ref(),\n                }\n            }\n        }\n    };\n}\n\ngen_listener_kinds! {\n    onabort\n    onauxclick\n    onblur\n    oncancel\n    oncanplay\n    oncanplaythrough\n    onchange\n    onclick\n    onclose\n    oncontextmenu\n    oncuechange\n    ondblclick\n    ondrag\n    ondragend\n    ondragenter\n    ondragexit\n    ondragleave\n    ondragover\n    ondragstart\n    ondrop\n    ondurationchange\n    onemptied\n    onended\n    onerror\n    onfocus\n    onfocusin\n    onfocusout\n    onformdata\n    oninput\n    oninvalid\n    onkeydown\n    onkeypress\n    onkeyup\n    onload\n    onloadeddata\n    onloadedmetadata\n    onloadstart\n    onmousedown\n    onmouseenter\n    onmouseleave\n    onmousemove\n    onmouseout\n    onmouseover\n    onmouseup\n    onpause\n    onplay\n    onplaying\n    onprogress\n    onratechange\n    onreset\n    onresize\n    onscroll\n    onsecuritypolicyviolation\n    onseeked\n    onseeking\n    onselect\n    onslotchange\n    onstalled\n    onsubmit\n    onsuspend\n    ontimeupdate\n    ontoggle\n    onvolumechange\n    onwaiting\n    onwheel\n    oncopy\n    oncut\n    onpaste\n    onanimationcancel\n    onanimationend\n    onanimationiteration\n    onanimationstart\n    ongotpointercapture\n    onloadend\n    onlostpointercapture\n    onpointercancel\n    onpointerdown\n    onpointerenter\n    onpointerleave\n    onpointerlockchange\n    onpointerlockerror\n    onpointermove\n    onpointerout\n    onpointerover\n    onpointerup\n    onselectionchange\n    onselectstart\n    onshow\n    ontouchcancel\n    ontouchend\n    ontouchmove\n    ontouchstart\n    ontransitioncancel\n    ontransitionend\n    ontransitionrun\n    ontransitionstart\n}\n\n/// A list of event listeners\n#[derive(Debug, Clone, ImplicitClone, Default)]\npub enum Listeners {\n    /// No listeners registered or pending.\n    /// Distinct from `Pending` with an empty slice to avoid an allocation.\n    #[default]\n    None,\n\n    /// Not yet added to the element or registry\n    Pending(Box<[Option<Rc<dyn Listener>>]>),\n}\n\nimpl PartialEq for Listeners {\n    fn eq(&self, rhs: &Self) -> bool {\n        use Listeners::*;\n\n        match (self, rhs) {\n            (None, None) => true,\n            (Pending(lhs), Pending(rhs)) => {\n                if lhs.len() != rhs.len() {\n                    false\n                } else {\n                    use std::option::Option::None;\n\n                    lhs.iter()\n                        .zip(rhs.iter())\n                        .all(|(lhs, rhs)| match (lhs, rhs) {\n                            (Some(lhs), Some(rhs)) => {\n                                // We are okay with comparisons from different compilation units to\n                                // result in false not-equal results. This should only lead in the\n                                // worst-case to some unneeded re-renders.\n                                #[allow(ambiguous_wide_pointer_comparisons)]\n                                Rc::ptr_eq(lhs, rhs)\n                            }\n                            (None, None) => true,\n                            _ => false,\n                        })\n                }\n            }\n            (None, Pending(pending)) | (Pending(pending), None) => pending.is_empty(),\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/mod.rs",
    "content": "//! This module contains Yew's implementation of a reactive virtual DOM.\n\n#[doc(hidden)]\npub mod key;\n#[doc(hidden)]\npub mod listeners;\n#[doc(hidden)]\npub mod vcomp;\n#[doc(hidden)]\npub mod vlist;\n#[doc(hidden)]\npub mod vnode;\n#[doc(hidden)]\npub mod vportal;\n#[doc(hidden)]\npub mod vraw;\n#[doc(hidden)]\npub mod vsuspense;\n#[doc(hidden)]\npub mod vtag;\n#[doc(hidden)]\npub mod vtext;\n\nuse std::hint::unreachable_unchecked;\nuse std::rc::Rc;\n\nuse indexmap::IndexMap;\nuse wasm_bindgen::JsValue;\n\n#[doc(inline)]\npub use self::key::Key;\n#[doc(inline)]\npub use self::listeners::*;\n#[doc(inline)]\npub use self::vcomp::{VChild, VComp};\n#[doc(hidden)]\npub use self::vlist::FullyKeyedState;\n#[doc(inline)]\npub use self::vlist::VList;\n#[doc(inline)]\npub use self::vnode::VNode;\n#[doc(inline)]\npub use self::vportal::VPortal;\n#[doc(inline)]\npub use self::vraw::VRaw;\n#[doc(inline)]\npub use self::vsuspense::VSuspense;\n#[doc(inline)]\npub use self::vtag::VTag;\n#[doc(inline)]\npub use self::vtext::VText;\n\n/// Attribute value\npub type AttrValue = implicit_clone::unsync::IString;\n\n#[cfg(any(feature = \"ssr\", feature = \"hydration\"))]\nmod feat_ssr_hydration {\n    #[cfg(debug_assertions)]\n    type ComponentName = &'static str;\n    #[cfg(not(debug_assertions))]\n    type ComponentName = std::marker::PhantomData<()>;\n\n    #[cfg(feature = \"hydration\")]\n    use std::borrow::Cow;\n\n    /// A collectable.\n    ///\n    /// This indicates a kind that can be collected from fragment to be processed at a later time\n    pub enum Collectable {\n        Component(ComponentName),\n        Raw,\n        Suspense,\n    }\n\n    impl Collectable {\n        #[cfg(not(debug_assertions))]\n        #[inline(always)]\n        pub fn for_component<T: 'static>() -> Self {\n            use std::marker::PhantomData;\n            // This suppresses the clippy lint about unused generic.\n            // We inline this function\n            // so the function body is copied to its caller and generics get optimised away.\n            let _comp_type: PhantomData<T> = PhantomData;\n            Self::Component(PhantomData)\n        }\n\n        #[cfg(debug_assertions)]\n        pub fn for_component<T: 'static>() -> Self {\n            let comp_name = std::any::type_name::<T>();\n            Self::Component(comp_name)\n        }\n\n        pub fn open_start_mark(&self) -> &'static str {\n            match self {\n                Self::Component(_) => \"<[\",\n                Self::Raw => \"<#\",\n                Self::Suspense => \"<?\",\n            }\n        }\n\n        pub fn close_start_mark(&self) -> &'static str {\n            match self {\n                Self::Component(_) => \"</[\",\n                Self::Raw => \"</#\",\n                Self::Suspense => \"</?\",\n            }\n        }\n\n        pub fn end_mark(&self) -> &'static str {\n            match self {\n                Self::Component(_) => \"]>\",\n                Self::Raw => \">\",\n                Self::Suspense => \">\",\n            }\n        }\n\n        #[cfg(feature = \"hydration\")]\n        pub fn name(&self) -> Cow<'static, str> {\n            match self {\n                #[cfg(debug_assertions)]\n                Self::Component(m) => format!(\"Component({m})\").into(),\n                #[cfg(not(debug_assertions))]\n                Self::Component(_) => \"Component\".into(),\n                Self::Raw => \"Raw\".into(),\n                Self::Suspense => \"Suspense\".into(),\n            }\n        }\n    }\n}\n\n#[cfg(any(feature = \"ssr\", feature = \"hydration\"))]\npub(crate) use feat_ssr_hydration::*;\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use std::fmt::Write;\n\n    use super::*;\n    use crate::platform::fmt::BufWriter;\n\n    impl Collectable {\n        pub(crate) fn write_open_tag(&self, w: &mut BufWriter) {\n            let _ = w.write_str(\"<!--\");\n            let _ = w.write_str(self.open_start_mark());\n\n            #[cfg(debug_assertions)]\n            match self {\n                Self::Component(type_name) => {\n                    let _ = w.write_str(type_name);\n                }\n                Self::Raw => {}\n                Self::Suspense => {}\n            }\n\n            let _ = w.write_str(self.end_mark());\n            let _ = w.write_str(\"-->\");\n        }\n\n        pub(crate) fn write_close_tag(&self, w: &mut BufWriter) {\n            let _ = w.write_str(\"<!--\");\n            let _ = w.write_str(self.close_start_mark());\n\n            #[cfg(debug_assertions)]\n            match self {\n                Self::Component(type_name) => {\n                    let _ = w.write_str(type_name);\n                }\n                Self::Raw => {}\n                Self::Suspense => {}\n            }\n\n            let _ = w.write_str(self.end_mark());\n            let _ = w.write_str(\"-->\");\n        }\n    }\n}\n\n/// Defines if the [`Attributes`] is set as element's attribute or property and its value.\n#[allow(missing_docs)]\n#[derive(PartialEq, Clone, Debug)]\npub enum AttributeOrProperty {\n    // This exists as a workaround to support Rust <1.72\n    // Previous versions of Rust did not See\n    // `AttributeOrProperty::Attribute(AttrValue::Static(_))` as `'static` that html! macro\n    // used, and thus failed with \"temporary value dropped while borrowed\"\n    //\n    // See: https://github.com/yewstack/yew/pull/3458#discussion_r1350362215\n    Static(&'static str),\n    Attribute(AttrValue),\n    Property(JsValue),\n}\n\n/// A collection of attributes for an element\n#[derive(PartialEq, Clone, Debug)]\npub enum Attributes {\n    /// Static list of attributes.\n    ///\n    /// Allows optimizing comparison to a simple pointer equality check and reducing allocations,\n    /// if the attributes do not change on a node.\n    Static(&'static [(&'static str, AttributeOrProperty)]),\n\n    /// Static list of attribute keys with possibility to exclude attributes and dynamic attribute\n    /// values.\n    ///\n    /// Allows optimizing comparison to a simple pointer equality check and reducing allocations,\n    /// if the attributes keys do not change on a node.\n    Dynamic {\n        /// Attribute keys. Includes both always set and optional attribute keys.\n        keys: &'static [&'static str],\n\n        /// Attribute values. Matches [keys](Attributes::Dynamic::keys). Optional attributes are\n        /// designated by setting [None].\n        values: Box<[Option<AttributeOrProperty>]>,\n    },\n\n    /// IndexMap is used to provide runtime attribute deduplication in cases where the html! macro\n    /// was not used to guarantee it.\n    IndexMap(Rc<IndexMap<AttrValue, AttributeOrProperty>>),\n}\n\nimpl Attributes {\n    /// Construct a default Attributes instance\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Return iterator over attribute key-value pairs.\n    /// This function is suboptimal and does not inline well. Avoid on hot paths.\n    ///\n    /// This function only returns attributes\n    pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a str)> + 'a> {\n        match self {\n            Self::Static(arr) => Box::new(arr.iter().filter_map(|(k, v)| match v {\n                AttributeOrProperty::Attribute(v) => Some((*k, v.as_ref())),\n                AttributeOrProperty::Property(_) => None,\n                AttributeOrProperty::Static(v) => Some((*k, v)),\n            })),\n            Self::Dynamic { keys, values } => {\n                Box::new(keys.iter().zip(values.iter()).filter_map(|(k, v)| match v {\n                    Some(AttributeOrProperty::Attribute(v)) => Some((*k, v.as_ref())),\n                    _ => None,\n                }))\n            }\n            Self::IndexMap(m) => Box::new(m.iter().filter_map(|(k, v)| match v {\n                AttributeOrProperty::Attribute(v) => Some((k.as_ref(), v.as_ref())),\n                _ => None,\n            })),\n        }\n    }\n\n    /// Get a mutable reference to the underlying `IndexMap`.\n    /// If the attributes are stored in the `Vec` variant, it will be converted.\n    pub fn get_mut_index_map(&mut self) -> &mut IndexMap<AttrValue, AttributeOrProperty> {\n        macro_rules! unpack {\n            () => {\n                match self {\n                    Self::IndexMap(m) => Rc::make_mut(m),\n                    // SAFETY: unreachable because we set self to the `IndexMap` variant above.\n                    _ => unsafe { unreachable_unchecked() },\n                }\n            };\n        }\n\n        match self {\n            Self::IndexMap(m) => Rc::make_mut(m),\n            Self::Static(arr) => {\n                *self = Self::IndexMap(Rc::new(\n                    arr.iter().map(|(k, v)| ((*k).into(), v.clone())).collect(),\n                ));\n                unpack!()\n            }\n            Self::Dynamic { keys, values } => {\n                *self = Self::IndexMap(Rc::new(\n                    std::mem::take(values)\n                        .iter_mut()\n                        .zip(keys.iter())\n                        .filter_map(|(v, k)| v.take().map(|v| (AttrValue::from(*k), v)))\n                        .collect(),\n                ));\n                unpack!()\n            }\n        }\n    }\n}\n\nimpl From<IndexMap<AttrValue, AttrValue>> for Attributes {\n    fn from(map: IndexMap<AttrValue, AttrValue>) -> Self {\n        let v = map\n            .into_iter()\n            .map(|(k, v)| (k, AttributeOrProperty::Attribute(v)))\n            .collect();\n        Self::IndexMap(Rc::new(v))\n    }\n}\n\nimpl From<IndexMap<&'static str, AttrValue>> for Attributes {\n    fn from(v: IndexMap<&'static str, AttrValue>) -> Self {\n        let v = v\n            .into_iter()\n            .map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Attribute(v))))\n            .collect();\n        Self::IndexMap(Rc::new(v))\n    }\n}\n\nimpl From<IndexMap<&'static str, JsValue>> for Attributes {\n    fn from(v: IndexMap<&'static str, JsValue>) -> Self {\n        let v = v\n            .into_iter()\n            .map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Property(v))))\n            .collect();\n        Self::IndexMap(Rc::new(v))\n    }\n}\n\nimpl Default for Attributes {\n    fn default() -> Self {\n        Self::Static(&[])\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vcomp.rs",
    "content": "//! This module contains the implementation of a virtual component (`VComp`).\n\nuse std::any::{Any, TypeId};\nuse std::fmt;\nuse std::rc::Rc;\n\n#[cfg(feature = \"ssr\")]\nuse futures::future::{FutureExt, LocalBoxFuture};\n#[cfg(feature = \"csr\")]\nuse web_sys::Element;\n\nuse super::Key;\n#[cfg(feature = \"hydration\")]\nuse crate::dom_bundle::Fragment;\n#[cfg(feature = \"csr\")]\nuse crate::dom_bundle::{BSubtree, DomSlot, DynamicDomSlot};\nuse crate::html::BaseComponent;\n#[cfg(feature = \"csr\")]\nuse crate::html::Scoped;\n#[cfg(any(feature = \"ssr\", feature = \"csr\"))]\nuse crate::html::{AnyScope, Scope};\n#[cfg(feature = \"ssr\")]\nuse crate::{feat_ssr::VTagKind, platform::fmt::BufWriter};\n\n/// A virtual component.\npub struct VComp {\n    pub(crate) type_id: TypeId,\n    pub(crate) mountable: Box<dyn Mountable>,\n    pub(crate) key: Option<Key>,\n    // for some reason, this reduces the bundle size by ~2-3 KBs\n    _marker: u32,\n}\n\nimpl fmt::Debug for VComp {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"VComp\")\n            .field(\"type_id\", &self.type_id)\n            .field(\"mountable\", &\"..\")\n            .field(\"key\", &self.key)\n            .finish()\n    }\n}\n\nimpl Clone for VComp {\n    fn clone(&self) -> Self {\n        Self {\n            type_id: self.type_id,\n            mountable: self.mountable.copy(),\n            key: self.key.clone(),\n            _marker: 0,\n        }\n    }\n}\n\npub(crate) trait Mountable {\n    fn copy(&self) -> Box<dyn Mountable>;\n\n    fn mountable_eq(&self, rhs: &dyn Mountable) -> bool;\n    fn as_any(&self) -> &dyn Any;\n\n    #[cfg(feature = \"csr\")]\n    fn mount(\n        self: Box<Self>,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: Element,\n        slot: DomSlot,\n    ) -> (Box<dyn Scoped>, DynamicDomSlot);\n\n    #[cfg(feature = \"csr\")]\n    fn reuse(self: Box<Self>, scope: &dyn Scoped, slot: DomSlot);\n\n    #[cfg(feature = \"ssr\")]\n    fn render_into_stream<'a>(\n        &'a self,\n        w: &'a mut BufWriter,\n        parent_scope: &'a AnyScope,\n        hydratable: bool,\n        parent_vtag_kind: VTagKind,\n    ) -> LocalBoxFuture<'a, ()>;\n\n    #[cfg(feature = \"hydration\")]\n    fn hydrate(\n        self: Box<Self>,\n        root: BSubtree,\n        parent_scope: &AnyScope,\n        parent: Element,\n        fragment: &mut Fragment,\n        prev_next_sibling: &mut Option<DynamicDomSlot>,\n    ) -> (Box<dyn Scoped>, DynamicDomSlot);\n}\n\npub(crate) struct PropsWrapper<COMP: BaseComponent> {\n    props: Rc<COMP::Properties>,\n}\n\nimpl<COMP: BaseComponent> PropsWrapper<COMP> {\n    pub fn new(props: Rc<COMP::Properties>) -> Self {\n        Self { props }\n    }\n}\n\nimpl<COMP: BaseComponent> Mountable for PropsWrapper<COMP> {\n    fn copy(&self) -> Box<dyn Mountable> {\n        let wrapper: PropsWrapper<COMP> = PropsWrapper {\n            props: Rc::clone(&self.props),\n        };\n        Box::new(wrapper)\n    }\n\n    fn as_any(&self) -> &dyn Any {\n        self\n    }\n\n    fn mountable_eq(&self, rhs: &dyn Mountable) -> bool {\n        rhs.as_any()\n            .downcast_ref::<Self>()\n            .map(|rhs| self.props == rhs.props)\n            .unwrap_or(false)\n    }\n\n    #[cfg(feature = \"csr\")]\n    fn mount(\n        self: Box<Self>,\n        root: &BSubtree,\n        parent_scope: &AnyScope,\n        parent: Element,\n        slot: DomSlot,\n    ) -> (Box<dyn Scoped>, DynamicDomSlot) {\n        let scope: Scope<COMP> = Scope::new(Some(parent_scope.clone()));\n        let own_slot = scope.mount_in_place(root.clone(), parent, slot, self.props);\n\n        (Box::new(scope), own_slot)\n    }\n\n    #[cfg(feature = \"csr\")]\n    fn reuse(self: Box<Self>, scope: &dyn Scoped, slot: DomSlot) {\n        let scope: Scope<COMP> = scope.to_any().downcast::<COMP>();\n        scope.reuse(self.props, slot);\n    }\n\n    #[cfg(feature = \"ssr\")]\n    fn render_into_stream<'a>(\n        &'a self,\n        w: &'a mut BufWriter,\n        parent_scope: &'a AnyScope,\n        hydratable: bool,\n        parent_vtag_kind: VTagKind,\n    ) -> LocalBoxFuture<'a, ()> {\n        let scope: Scope<COMP> = Scope::new(Some(parent_scope.clone()));\n\n        async move {\n            scope\n                .render_into_stream(w, self.props.clone(), hydratable, parent_vtag_kind)\n                .await;\n        }\n        .boxed_local()\n    }\n\n    #[cfg(feature = \"hydration\")]\n    fn hydrate(\n        self: Box<Self>,\n        root: BSubtree,\n        parent_scope: &AnyScope,\n        parent: Element,\n        fragment: &mut Fragment,\n        prev_next_sibling: &mut Option<DynamicDomSlot>,\n    ) -> (Box<dyn Scoped>, DynamicDomSlot) {\n        let scope: Scope<COMP> = Scope::new(Some(parent_scope.clone()));\n        let own_slot =\n            scope.hydrate_in_place(root, parent, fragment, self.props, prev_next_sibling);\n\n        (Box::new(scope), own_slot)\n    }\n}\n\n/// A virtual child component.\npub struct VChild<COMP: BaseComponent> {\n    /// The component properties\n    pub props: Rc<COMP::Properties>,\n    /// Reference to the mounted node\n    key: Option<Key>,\n}\n\nimpl<COMP: BaseComponent> implicit_clone::ImplicitClone for VChild<COMP> {}\n\nimpl<COMP: BaseComponent> Clone for VChild<COMP> {\n    fn clone(&self) -> Self {\n        VChild {\n            props: Rc::clone(&self.props),\n            key: self.key.clone(),\n        }\n    }\n}\n\nimpl<COMP: BaseComponent> PartialEq for VChild<COMP>\nwhere\n    COMP::Properties: PartialEq,\n{\n    fn eq(&self, other: &VChild<COMP>) -> bool {\n        self.props == other.props\n    }\n}\n\nimpl<COMP> VChild<COMP>\nwhere\n    COMP: BaseComponent,\n{\n    /// Creates a child component that can be accessed and modified by its parent.\n    pub fn new(props: COMP::Properties, key: Option<Key>) -> Self {\n        Self {\n            props: Rc::new(props),\n            key,\n        }\n    }\n}\n\nimpl<COMP> VChild<COMP>\nwhere\n    COMP: BaseComponent,\n    COMP::Properties: Clone,\n{\n    /// Get a mutable reference to the underlying properties.\n    pub fn get_mut(&mut self) -> &mut COMP::Properties {\n        Rc::make_mut(&mut self.props)\n    }\n}\n\nimpl<COMP> From<VChild<COMP>> for VComp\nwhere\n    COMP: BaseComponent,\n{\n    fn from(vchild: VChild<COMP>) -> Self {\n        VComp::new::<COMP>(vchild.props, vchild.key)\n    }\n}\n\nimpl VComp {\n    /// Creates a new `VComp` instance.\n    pub fn new<COMP>(props: Rc<COMP::Properties>, key: Option<Key>) -> Self\n    where\n        COMP: BaseComponent,\n    {\n        VComp {\n            type_id: TypeId::of::<COMP>(),\n            mountable: Box::new(PropsWrapper::<COMP>::new(props)),\n            key,\n            _marker: 0,\n        }\n    }\n}\n\nimpl PartialEq for VComp {\n    fn eq(&self, other: &VComp) -> bool {\n        self.key == other.key\n            && self.type_id == other.type_id\n            && self.mountable.mountable_eq(other.mountable.as_ref())\n    }\n}\n\nimpl<COMP: BaseComponent> fmt::Debug for VChild<COMP> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"VChild<_>\")\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use super::*;\n    use crate::html::AnyScope;\n\n    impl VComp {\n        #[inline]\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            parent_scope: &AnyScope,\n            hydratable: bool,\n            parent_vtag_kind: VTagKind,\n        ) {\n            self.mountable\n                .as_ref()\n                .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                .await;\n        }\n    }\n}\n\n#[cfg(all(test, not(target_arch = \"wasm32\"), feature = \"ssr\"))]\nmod ssr_tests {\n    use tokio::test;\n\n    use crate::prelude::*;\n    use crate::ServerRenderer;\n\n    #[test]\n    async fn test_props() {\n        #[derive(PartialEq, Properties, Debug)]\n        struct ChildProps {\n            name: String,\n        }\n\n        #[component]\n        fn Child(props: &ChildProps) -> Html {\n            html! { <div>{\"Hello, \"}{&props.name}{\"!\"}</div> }\n        }\n\n        #[component]\n        fn Comp() -> Html {\n            html! {\n                <div>\n                    <Child name=\"Jane\" />\n                    <Child name=\"John\" />\n                    <Child name=\"Josh\" />\n                </div>\n            }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(\n            s,\n            \"<div><div>Hello, Jane!</div><div>Hello, John!</div><div>Hello, Josh!</div></div>\"\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vlist.rs",
    "content": "//! This module contains fragments implementation.\nuse std::ops::{Deref, DerefMut};\nuse std::rc::Rc;\n\nuse super::{Key, VNode};\n\n#[doc(hidden)]\n#[derive(Clone, Copy, Debug, PartialEq)]\npub enum FullyKeyedState {\n    KnownFullyKeyed,\n    KnownMissingKeys,\n    Unknown,\n}\n\n/// This struct represents a fragment of the Virtual DOM tree.\n#[derive(Clone, Debug)]\npub struct VList {\n    /// The list of child [VNode]s\n    pub(crate) children: Option<Rc<Vec<VNode>>>,\n\n    /// All [VNode]s in the VList have keys\n    fully_keyed: FullyKeyedState,\n\n    pub key: Option<Key>,\n}\n\nimpl PartialEq for VList {\n    fn eq(&self, other: &Self) -> bool {\n        if self.key != other.key {\n            return false;\n        }\n\n        match (self.children.as_ref(), other.children.as_ref()) {\n            (Some(a), Some(b)) => a == b,\n            (Some(a), None) => a.is_empty(),\n            (None, Some(b)) => b.is_empty(),\n            (None, None) => true,\n        }\n    }\n}\n\nimpl Default for VList {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Deref for VList {\n    type Target = Vec<VNode>;\n\n    fn deref(&self) -> &Self::Target {\n        match self.children {\n            Some(ref m) => m,\n            None => {\n                // This can be replaced with `const { &Vec::new() }` in Rust 1.79.\n                const EMPTY: &Vec<VNode> = &Vec::new();\n                EMPTY\n            }\n        }\n    }\n}\n\nimpl DerefMut for VList {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.fully_keyed = FullyKeyedState::Unknown;\n        self.children_mut()\n    }\n}\n\nimpl<A: Into<VNode>> FromIterator<A> for VList {\n    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {\n        let children = iter.into_iter().map(|n| n.into()).collect::<Vec<_>>();\n        if children.is_empty() {\n            VList::new()\n        } else {\n            VList {\n                children: Some(Rc::new(children)),\n                fully_keyed: FullyKeyedState::Unknown,\n                key: None,\n            }\n        }\n    }\n}\n\nimpl From<Option<Rc<Vec<VNode>>>> for VList {\n    fn from(children: Option<Rc<Vec<VNode>>>) -> Self {\n        if children.as_ref().map(|x| x.is_empty()).unwrap_or(true) {\n            VList::new()\n        } else {\n            let mut vlist = VList {\n                children,\n                fully_keyed: FullyKeyedState::Unknown,\n                key: None,\n            };\n            vlist.recheck_fully_keyed();\n            vlist\n        }\n    }\n}\n\nimpl From<Vec<VNode>> for VList {\n    fn from(children: Vec<VNode>) -> Self {\n        if children.is_empty() {\n            VList::new()\n        } else {\n            let mut vlist = VList {\n                children: Some(Rc::new(children)),\n                fully_keyed: FullyKeyedState::Unknown,\n                key: None,\n            };\n            vlist.recheck_fully_keyed();\n            vlist\n        }\n    }\n}\n\nimpl From<VNode> for VList {\n    fn from(child: VNode) -> Self {\n        let mut vlist = VList {\n            children: Some(Rc::new(vec![child])),\n            fully_keyed: FullyKeyedState::Unknown,\n            key: None,\n        };\n        vlist.recheck_fully_keyed();\n        vlist\n    }\n}\n\nimpl VList {\n    /// Creates a new empty [VList] instance.\n    pub const fn new() -> Self {\n        Self {\n            children: None,\n            key: None,\n            fully_keyed: FullyKeyedState::KnownFullyKeyed,\n        }\n    }\n\n    /// Creates a new [VList] instance with children.\n    pub fn with_children(children: Vec<VNode>, key: Option<Key>) -> Self {\n        let mut vlist = VList::from(children);\n        vlist.key = key;\n        vlist\n    }\n\n    #[doc(hidden)]\n    /// Used by `html!` to avoid calling `.recheck_fully_keyed()` when possible.\n    pub fn __macro_new(\n        children: Vec<VNode>,\n        key: Option<Key>,\n        fully_keyed: FullyKeyedState,\n    ) -> Self {\n        VList {\n            children: Some(Rc::new(children)),\n            fully_keyed,\n            key,\n        }\n    }\n\n    // Returns a mutable reference to children, allocates the children if it hasn't been done.\n    //\n    // This method does not reassign key state. So it should only be used internally.\n    fn children_mut(&mut self) -> &mut Vec<VNode> {\n        loop {\n            match self.children {\n                Some(ref mut m) => return Rc::make_mut(m),\n                None => {\n                    self.children = Some(Rc::new(Vec::new()));\n                }\n            }\n        }\n    }\n\n    /// Add [VNode] child.\n    pub fn add_child(&mut self, child: VNode) {\n        if self.fully_keyed == FullyKeyedState::KnownFullyKeyed && !child.has_key() {\n            self.fully_keyed = FullyKeyedState::KnownMissingKeys;\n        }\n        self.children_mut().push(child);\n    }\n\n    /// Add multiple [VNode] children.\n    pub fn add_children(&mut self, children: impl IntoIterator<Item = VNode>) {\n        let it = children.into_iter();\n        let bound = it.size_hint();\n        self.children_mut().reserve(bound.1.unwrap_or(bound.0));\n        for ch in it {\n            self.add_child(ch);\n        }\n    }\n\n    /// Recheck, if the all the children have keys.\n    ///\n    /// You can run this, after modifying the child list through the [DerefMut] implementation of\n    /// [VList], to precompute an internally kept flag, which speeds up reconciliation later.\n    pub fn recheck_fully_keyed(&mut self) {\n        self.fully_keyed = if self.fully_keyed() {\n            FullyKeyedState::KnownFullyKeyed\n        } else {\n            FullyKeyedState::KnownMissingKeys\n        };\n    }\n\n    pub(crate) fn fully_keyed(&self) -> bool {\n        match self.fully_keyed {\n            FullyKeyedState::KnownFullyKeyed => true,\n            FullyKeyedState::KnownMissingKeys => false,\n            FullyKeyedState::Unknown => self.iter().all(|c| c.has_key()),\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use crate::virtual_dom::{VTag, VText};\n\n    #[test]\n    fn mutably_change_children() {\n        let mut vlist = VList::new();\n        assert_eq!(\n            vlist.fully_keyed,\n            FullyKeyedState::KnownFullyKeyed,\n            \"should start fully keyed\"\n        );\n        // add a child that is keyed\n        vlist.add_child(VNode::VTag({\n            let mut tag = VTag::new(\"a\");\n            tag.key = Some(42u32.into());\n            tag.into()\n        }));\n        assert_eq!(\n            vlist.fully_keyed,\n            FullyKeyedState::KnownFullyKeyed,\n            \"should still be fully keyed\"\n        );\n        assert_eq!(vlist.len(), 1, \"should contain 1 child\");\n        // now add a child that is not keyed\n        vlist.add_child(VNode::VText(VText::new(\"lorem ipsum\")));\n        assert_eq!(\n            vlist.fully_keyed,\n            FullyKeyedState::KnownMissingKeys,\n            \"should not be fully keyed, text tags have no key\"\n        );\n        let _: &mut [VNode] = &mut vlist; // Use deref mut\n        assert_eq!(\n            vlist.fully_keyed,\n            FullyKeyedState::Unknown,\n            \"key state should be unknown, since it was potentially modified through children\"\n        );\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use std::fmt::Write;\n    use std::task::Poll;\n\n    use futures::stream::StreamExt;\n    use futures::{join, pin_mut, poll, FutureExt};\n\n    use super::*;\n    use crate::feat_ssr::VTagKind;\n    use crate::html::AnyScope;\n    use crate::platform::fmt::{self, BufWriter};\n\n    impl VList {\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            parent_scope: &AnyScope,\n            hydratable: bool,\n            parent_vtag_kind: VTagKind,\n        ) {\n            match &self[..] {\n                [] => {}\n                [child] => {\n                    child\n                        .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                        .await;\n                }\n                _ => {\n                    async fn render_child_iter<'a, I>(\n                        mut children: I,\n                        w: &mut BufWriter,\n                        parent_scope: &AnyScope,\n                        hydratable: bool,\n                        parent_vtag_kind: VTagKind,\n                    ) where\n                        I: Iterator<Item = &'a VNode>,\n                    {\n                        let mut w = w;\n                        while let Some(m) = children.next() {\n                            let child_fur = async move {\n                                // Rust's Compiler does not release the mutable reference to\n                                // BufWriter until the end of the loop, regardless of whether an\n                                // await statement has dropped the child_fur.\n                                //\n                                // We capture and return the mutable reference to avoid this.\n\n                                m.render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                                    .await;\n                                w\n                            };\n                            pin_mut!(child_fur);\n\n                            match poll!(child_fur.as_mut()) {\n                                Poll::Pending => {\n                                    let (mut next_w, next_r) = fmt::buffer();\n                                    // Move buf writer into an async block for it to be dropped at\n                                    // the end of the future.\n                                    let rest_render_fur = async move {\n                                        render_child_iter(\n                                            children,\n                                            &mut next_w,\n                                            parent_scope,\n                                            hydratable,\n                                            parent_vtag_kind,\n                                        )\n                                        .await;\n                                    }\n                                    // boxing to avoid recursion\n                                    .boxed_local();\n\n                                    let transfer_fur = async move {\n                                        let w = child_fur.await;\n\n                                        pin_mut!(next_r);\n                                        while let Some(m) = next_r.next().await {\n                                            let _ = w.write_str(m.as_str());\n                                        }\n                                    };\n\n                                    join!(rest_render_fur, transfer_fur);\n                                    break;\n                                }\n                                Poll::Ready(w_) => {\n                                    w = w_;\n                                }\n                            }\n                        }\n                    }\n\n                    let children = self.iter();\n                    render_child_iter(children, w, parent_scope, hydratable, parent_vtag_kind)\n                        .await;\n                }\n            }\n        }\n    }\n}\n\n#[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\n#[cfg(feature = \"ssr\")]\n#[cfg(test)]\nmod ssr_tests {\n    use tokio::test;\n\n    use crate::prelude::*;\n    use crate::LocalServerRenderer as ServerRenderer;\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_text_back_to_back() {\n        #[component]\n        fn Comp() -> Html {\n            let s = \"world\";\n\n            html! { <div>{\"Hello \"}{s}{\"!\"}</div> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, \"<div>Hello world!</div>\");\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_fragment() {\n        #[derive(PartialEq, Properties, Debug)]\n        struct ChildProps {\n            name: String,\n        }\n\n        #[component]\n        fn Child(props: &ChildProps) -> Html {\n            html! { <div>{\"Hello, \"}{&props.name}{\"!\"}</div> }\n        }\n\n        #[component]\n        fn Comp() -> Html {\n            html! {\n                <>\n                    <Child name=\"Jane\" />\n                    <Child name=\"John\" />\n                    <Child name=\"Josh\" />\n                </>\n            }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(\n            s,\n            \"<div>Hello, Jane!</div><div>Hello, John!</div><div>Hello, Josh!</div>\"\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vnode.rs",
    "content": "//! This module contains the implementation of abstract virtual node.\n\nuse std::cmp::PartialEq;\nuse std::iter::FromIterator;\nuse std::rc::Rc;\nuse std::{fmt, mem};\n\nuse web_sys::Node;\n\nuse super::{Key, VChild, VComp, VList, VPortal, VSuspense, VTag, VText};\nuse crate::html::{BaseComponent, ImplicitClone};\nuse crate::virtual_dom::VRaw;\nuse crate::AttrValue;\n\n/// Bind virtual element to a DOM reference.\n#[derive(Clone, ImplicitClone, PartialEq)]\n#[must_use = \"html does not do anything unless returned to Yew for rendering.\"]\npub enum VNode {\n    /// A bind between `VTag` and `Element`.\n    VTag(Rc<VTag>),\n    /// A bind between `VText` and `TextNode`.\n    VText(VText),\n    /// A bind between `VComp` and `Element`.\n    VComp(Rc<VComp>),\n    /// A holder for a list of other nodes.\n    VList(Rc<VList>),\n    /// A portal to another part of the document\n    VPortal(Rc<VPortal>),\n    /// A holder for any `Node` (necessary for replacing node).\n    VRef(Node),\n    /// A suspendible document fragment.\n    VSuspense(Rc<VSuspense>),\n    /// A raw HTML string, represented by [`AttrValue`](crate::AttrValue).\n    ///\n    /// Also see: [`VNode::from_html_unchecked`]\n    VRaw(VRaw),\n}\n\nimpl VNode {\n    pub fn key(&self) -> Option<&Key> {\n        match self {\n            VNode::VComp(vcomp) => vcomp.key.as_ref(),\n            VNode::VList(vlist) => vlist.key.as_ref(),\n            VNode::VRef(_) => None,\n            VNode::VTag(vtag) => vtag.key.as_ref(),\n            VNode::VText(_) => None,\n            VNode::VPortal(vportal) => vportal.node.key(),\n            VNode::VSuspense(vsuspense) => vsuspense.key.as_ref(),\n            VNode::VRaw(_) => None,\n        }\n    }\n\n    /// Returns true if the [VNode] has a key.\n    pub fn has_key(&self) -> bool {\n        self.key().is_some()\n    }\n\n    /// Acquires a mutable reference of current VNode as a VList.\n    ///\n    /// Creates a VList with the current node as the first child if current VNode is not a VList.\n    pub fn to_vlist_mut(&mut self) -> &mut VList {\n        loop {\n            match *self {\n                Self::VList(ref mut m) => return Rc::make_mut(m),\n                _ => {\n                    *self = VNode::VList(Rc::new(VList::from(mem::take(self))));\n                }\n            }\n        }\n    }\n\n    /// Create a [`VNode`] from a string of HTML\n    ///\n    /// # Behavior in browser\n    ///\n    /// In the browser, this function creates an element with the same XML namespace as the parent,\n    /// sets the passed HTML to its `innerHTML` and inserts the contents of it into the DOM.\n    ///\n    /// # Behavior on server\n    ///\n    /// When rendering on the server, the contents of HTML are directly injected into the HTML\n    /// stream.\n    ///\n    /// ## Warning\n    ///\n    /// The contents are **not** sanitized or validated. You, as the developer, are responsible to\n    /// ensure the HTML string passed to this method are _valid_ and _not malicious_\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use yew::{html, AttrValue, Html};\n    /// # fn _main() {\n    /// let parsed = Html::from_html_unchecked(AttrValue::from(\"<div>content</div>\"));\n    /// let _: Html = html! {\n    ///     <div>\n    ///         {parsed}\n    ///     </div>\n    /// };\n    /// # }\n    /// ```\n    pub fn from_html_unchecked(html: AttrValue) -> Self {\n        VNode::VRaw(VRaw { html })\n    }\n}\n\nimpl Default for VNode {\n    fn default() -> Self {\n        VNode::VList(Rc::new(VList::default()))\n    }\n}\n\nimpl From<VText> for VNode {\n    #[inline]\n    fn from(vtext: VText) -> Self {\n        VNode::VText(vtext)\n    }\n}\n\nimpl From<VList> for VNode {\n    #[inline]\n    fn from(vlist: VList) -> Self {\n        VNode::VList(Rc::new(vlist))\n    }\n}\n\nimpl From<VTag> for VNode {\n    #[inline]\n    fn from(vtag: VTag) -> Self {\n        VNode::VTag(Rc::new(vtag))\n    }\n}\n\nimpl From<VComp> for VNode {\n    #[inline]\n    fn from(vcomp: VComp) -> Self {\n        VNode::VComp(Rc::new(vcomp))\n    }\n}\n\nimpl From<VSuspense> for VNode {\n    #[inline]\n    fn from(vsuspense: VSuspense) -> Self {\n        VNode::VSuspense(Rc::new(vsuspense))\n    }\n}\n\nimpl From<VPortal> for VNode {\n    #[inline]\n    fn from(vportal: VPortal) -> Self {\n        VNode::VPortal(Rc::new(vportal))\n    }\n}\n\nimpl<COMP> From<VChild<COMP>> for VNode\nwhere\n    COMP: BaseComponent,\n{\n    fn from(vchild: VChild<COMP>) -> Self {\n        VNode::VComp(Rc::new(VComp::from(vchild)))\n    }\n}\n\nimpl<T: ToString> From<T> for VNode {\n    fn from(value: T) -> Self {\n        VNode::VText(VText::new(value.to_string()))\n    }\n}\n\nimpl<A: Into<VNode>> FromIterator<A> for VNode {\n    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {\n        VNode::VList(Rc::new(VList::from_iter(\n            iter.into_iter().map(|n| n.into()),\n        )))\n    }\n}\n\nimpl fmt::Debug for VNode {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            VNode::VTag(ref vtag) => vtag.fmt(f),\n            VNode::VText(ref vtext) => vtext.fmt(f),\n            VNode::VComp(ref vcomp) => vcomp.fmt(f),\n            VNode::VList(ref vlist) => vlist.fmt(f),\n            VNode::VRef(ref vref) => write!(f, \"VRef ( \\\"{}\\\" )\", crate::utils::print_node(vref)),\n            VNode::VPortal(ref vportal) => vportal.fmt(f),\n            VNode::VSuspense(ref vsuspense) => vsuspense.fmt(f),\n            VNode::VRaw(ref vraw) => write!(f, \"VRaw {{ {} }}\", vraw.html),\n        }\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use futures::future::{FutureExt, LocalBoxFuture};\n\n    use super::*;\n    use crate::feat_ssr::VTagKind;\n    use crate::html::AnyScope;\n    use crate::platform::fmt::BufWriter;\n\n    impl VNode {\n        pub(crate) fn render_into_stream<'a>(\n            &'a self,\n            w: &'a mut BufWriter,\n            parent_scope: &'a AnyScope,\n            hydratable: bool,\n            parent_vtag_kind: VTagKind,\n        ) -> LocalBoxFuture<'a, ()> {\n            async fn render_into_stream_(\n                this: &VNode,\n                w: &mut BufWriter,\n                parent_scope: &AnyScope,\n                hydratable: bool,\n                parent_vtag_kind: VTagKind,\n            ) {\n                match this {\n                    VNode::VTag(vtag) => vtag.render_into_stream(w, parent_scope, hydratable).await,\n                    VNode::VText(vtext) => {\n                        vtext\n                            .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                            .await\n                    }\n                    VNode::VComp(vcomp) => {\n                        vcomp\n                            .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                            .await\n                    }\n                    VNode::VList(vlist) => {\n                        vlist\n                            .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                            .await\n                    }\n                    // We are pretty safe here as it's not possible to get a web_sys::Node without\n                    // DOM support in the first place.\n                    //\n                    // The only exception would be to use `ServerRenderer` in a browser or wasm32\n                    // environment with jsdom present.\n                    VNode::VRef(_) => {\n                        panic!(\"VRef is not possible to be rendered in to a string.\")\n                    }\n                    // Portals are not rendered.\n                    VNode::VPortal(_) => {}\n                    VNode::VSuspense(vsuspense) => {\n                        vsuspense\n                            .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                            .await\n                    }\n\n                    VNode::VRaw(vraw) => vraw.render_into_stream(w, parent_scope, hydratable).await,\n                }\n            }\n\n            async move {\n                render_into_stream_(self, w, parent_scope, hydratable, parent_vtag_kind).await\n            }.boxed_local()\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vportal.rs",
    "content": "//! This module contains the implementation of a portal `VPortal`.\n\nuse web_sys::{Element, Node};\n\nuse super::VNode;\n\n#[derive(Debug, Clone, PartialEq)]\npub struct VPortal {\n    /// The element under which the content is inserted.\n    pub host: Element,\n    /// The next sibling after the inserted content. Must be a child of `host`.\n    pub inner_sibling: Option<Node>,\n    /// The inserted node\n    pub node: VNode,\n}\n\nimpl VPortal {\n    /// Creates a [VPortal] rendering `content` in the DOM hierarchy under `host`.\n    pub fn new(content: VNode, host: Element) -> Self {\n        Self {\n            host,\n            inner_sibling: None,\n            node: content,\n        }\n    }\n\n    /// Creates a [VPortal] rendering `content` in the DOM hierarchy under `host`.\n    /// If `inner_sibling` is given, the content is inserted before that [Node].\n    /// The parent of `inner_sibling`, if given, must be `host`.\n    pub fn new_before(content: VNode, host: Element, inner_sibling: Option<Node>) -> Self {\n        Self {\n            host,\n            inner_sibling,\n            node: content,\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vraw.rs",
    "content": "use crate::html::ImplicitClone;\nuse crate::AttrValue;\n\n/// A raw HTML string to be used in VDOM.\n#[derive(Clone, ImplicitClone, Debug, PartialEq, Eq)]\npub struct VRaw {\n    pub html: AttrValue,\n}\n\nimpl From<AttrValue> for VRaw {\n    fn from(html: AttrValue) -> Self {\n        Self { html }\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use std::fmt::Write;\n\n    use super::*;\n    use crate::html::AnyScope;\n    use crate::platform::fmt::BufWriter;\n    use crate::virtual_dom::Collectable;\n\n    impl VRaw {\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            _parent_scope: &AnyScope,\n            hydratable: bool,\n        ) {\n            let collectable = Collectable::Raw;\n\n            if hydratable {\n                collectable.write_open_tag(w);\n            }\n\n            let _ = w.write_str(self.html.as_ref());\n\n            if hydratable {\n                collectable.write_close_tag(w);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vsuspense.rs",
    "content": "use super::{Key, VNode};\nuse crate::html::ImplicitClone;\n\n/// This struct represents a suspendable DOM fragment.\n#[derive(Clone, ImplicitClone, Debug, PartialEq)]\npub struct VSuspense {\n    /// Child nodes.\n    pub(crate) children: VNode,\n    /// Fallback nodes when suspended.\n    pub(crate) fallback: VNode,\n    /// Whether the current status is suspended.\n    pub(crate) suspended: bool,\n    /// The Key.\n    pub(crate) key: Option<Key>,\n}\n\nimpl VSuspense {\n    pub fn new(children: VNode, fallback: VNode, suspended: bool, key: Option<Key>) -> Self {\n        Self {\n            children,\n            fallback,\n            suspended,\n            key,\n        }\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use super::*;\n    use crate::feat_ssr::VTagKind;\n    use crate::html::AnyScope;\n    use crate::platform::fmt::BufWriter;\n    use crate::virtual_dom::Collectable;\n\n    impl VSuspense {\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            parent_scope: &AnyScope,\n            hydratable: bool,\n            parent_vtag_kind: VTagKind,\n        ) {\n            let collectable = Collectable::Suspense;\n\n            if hydratable {\n                collectable.write_open_tag(w);\n            }\n\n            // always render children on the server side.\n            self.children\n                .render_into_stream(w, parent_scope, hydratable, parent_vtag_kind)\n                .await;\n\n            if hydratable {\n                collectable.write_close_tag(w);\n            }\n        }\n    }\n}\n\n#[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\n#[cfg(feature = \"ssr\")]\n#[cfg(test)]\nmod ssr_tests {\n    use std::rc::Rc;\n    use std::time::Duration;\n\n    use tokio::task::{spawn_local, LocalSet};\n    use tokio::test;\n\n    use crate::platform::time::sleep;\n    use crate::prelude::*;\n    use crate::suspense::{Suspension, SuspensionResult};\n    use crate::ServerRenderer;\n\n    #[cfg(not(target_os = \"wasi\"))]\n    #[test(flavor = \"multi_thread\", worker_threads = 2)]\n    async fn test_suspense() {\n        #[derive(PartialEq)]\n        pub struct SleepState {\n            s: Suspension,\n        }\n\n        impl SleepState {\n            fn new() -> Self {\n                let (s, handle) = Suspension::new();\n\n                // we use tokio spawn local here.\n                spawn_local(async move {\n                    // we use tokio sleep here.\n                    sleep(Duration::from_millis(50)).await;\n\n                    handle.resume();\n                });\n\n                Self { s }\n            }\n        }\n\n        impl Reducible for SleepState {\n            type Action = ();\n\n            fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n                Self::new().into()\n            }\n        }\n\n        #[hook]\n        pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n            let sleep_state = use_reducer(SleepState::new);\n\n            if sleep_state.s.resumed() {\n                Ok(Rc::new(move || sleep_state.dispatch(())))\n            } else {\n                Err(sleep_state.s.clone())\n            }\n        }\n\n        #[derive(PartialEq, Properties, Debug)]\n        struct ChildProps {\n            name: String,\n        }\n\n        #[component]\n        fn Child(props: &ChildProps) -> HtmlResult {\n            use_sleep()?;\n            Ok(html! { <div>{\"Hello, \"}{&props.name}{\"!\"}</div> })\n        }\n\n        #[component]\n        fn Comp() -> Html {\n            let fallback = html! {\"loading...\"};\n\n            html! {\n                <Suspense {fallback}>\n                    <Child name=\"Jane\" />\n                    <Child name=\"John\" />\n                    <Child name=\"Josh\" />\n                </Suspense>\n            }\n        }\n\n        let local = LocalSet::new();\n\n        let s = local\n            .run_until(async move {\n                ServerRenderer::<Comp>::new()\n                    .hydratable(false)\n                    .render()\n                    .await\n            })\n            .await;\n\n        assert_eq!(\n            s,\n            \"<div>Hello, Jane!</div><div>Hello, John!</div><div>Hello, Josh!</div>\"\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vtag.rs",
    "content": "//! This module contains the implementation of a virtual element node [VTag].\n\nuse std::cmp::PartialEq;\nuse std::marker::PhantomData;\nuse std::mem;\nuse std::ops::{Deref, DerefMut};\nuse std::rc::Rc;\n\nuse wasm_bindgen::JsValue;\nuse web_sys::{HtmlInputElement as InputElement, HtmlTextAreaElement as TextAreaElement};\n\nuse super::{AttrValue, AttributeOrProperty, Attributes, Key, Listener, Listeners, VNode};\nuse crate::html::{ImplicitClone, IntoPropValue, NodeRef};\n\n/// SVG namespace string used for creating svg elements\npub const SVG_NAMESPACE: &str = \"http://www.w3.org/2000/svg\";\n\n/// MathML namespace string used for creating MathML elements\npub const MATHML_NAMESPACE: &str = \"http://www.w3.org/1998/Math/MathML\";\n\n/// Default namespace for html elements\npub const HTML_NAMESPACE: &str = \"http://www.w3.org/1999/xhtml\";\n\n/// Value field corresponding to an [Element]'s `value` property\n#[derive(Debug, Eq, PartialEq)]\npub(crate) struct Value<T>(Option<AttrValue>, PhantomData<T>);\n\nimpl<T> Clone for Value<T> {\n    fn clone(&self) -> Self {\n        Self::new(self.0.clone())\n    }\n}\n\nimpl<T> ImplicitClone for Value<T> {}\n\nimpl<T> Default for Value<T> {\n    fn default() -> Self {\n        Self::new(None)\n    }\n}\n\nimpl<T> Value<T> {\n    /// Create a new value. The caller should take care that the value is valid for the element's\n    /// `value` property\n    fn new(value: Option<AttrValue>) -> Self {\n        Value(value, PhantomData)\n    }\n\n    /// Set a new value. The caller should take care that the value is valid for the element's\n    /// `value` property\n    pub(crate) fn set(&mut self, value: Option<AttrValue>) {\n        self.0 = value;\n    }\n}\n\nimpl<T> Deref for Value<T> {\n    type Target = Option<AttrValue>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n/// Fields specific to\n/// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) [VTag](crate::virtual_dom::VTag)s\n#[derive(Debug, Clone, ImplicitClone, Default, Eq, PartialEq)]\npub(crate) struct InputFields {\n    /// Contains a value of an\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).\n    pub(crate) value: Value<InputElement>,\n    /// Represents `checked` attribute of\n    /// [input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-checked).\n    /// It exists to override standard behavior of `checked` attribute, because\n    /// in original HTML it sets `defaultChecked` value of `InputElement`, but for reactive\n    /// frameworks it's more useful to control `checked` value of an `InputElement`.\n    pub(crate) checked: Option<bool>,\n}\n\nimpl Deref for InputFields {\n    type Target = Value<InputElement>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.value\n    }\n}\n\nimpl DerefMut for InputFields {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.value\n    }\n}\n\nimpl InputFields {\n    /// Create new attributes for an [InputElement] element\n    fn new(value: Option<AttrValue>, checked: Option<bool>) -> Self {\n        Self {\n            value: Value::new(value),\n            checked,\n        }\n    }\n}\n\n#[derive(Debug, Clone, Default)]\npub(crate) struct TextareaFields {\n    /// Contains the value of an\n    /// [TextAreaElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea).\n    pub(crate) value: Value<TextAreaElement>,\n    /// Contains the default value of\n    /// [TextAreaElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea).\n    #[allow(unused)] // unused only if both \"csr\" and \"ssr\" features are off\n    pub(crate) defaultvalue: Option<AttrValue>,\n}\n\n/// [VTag] fields that are specific to different [VTag] kinds.\n/// Decreases the memory footprint of [VTag] by avoiding impossible field and value combinations.\n#[derive(Debug, Clone, ImplicitClone)]\npub(crate) enum VTagInner {\n    /// Fields specific to\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)\n    /// [VTag]s\n    Input(InputFields),\n    /// Fields specific to\n    /// [TextArea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)\n    /// [VTag]s\n    Textarea(TextareaFields),\n    /// Fields for all other kinds of [VTag]s\n    Other {\n        /// A tag of the element.\n        tag: AttrValue,\n        /// children of the element.\n        children: VNode,\n    },\n}\n\n/// A type for a virtual\n/// [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element)\n/// representation.\n#[derive(Debug, Clone, ImplicitClone)]\npub struct VTag {\n    /// [VTag] fields that are specific to different [VTag] kinds.\n    pub(crate) inner: VTagInner,\n    /// List of attached listeners.\n    pub(crate) listeners: Listeners,\n    /// A node reference used for DOM access in Component lifecycle methods\n    pub node_ref: NodeRef,\n    /// List of attributes.\n    pub attributes: Attributes,\n    pub key: Option<Key>,\n}\n\nimpl VTag {\n    /// Creates a new [VTag] instance with `tag` name (cannot be changed later in DOM).\n    pub fn new(tag: impl Into<AttrValue>) -> Self {\n        let tag = tag.into();\n        let lowercase_tag = tag.to_ascii_lowercase();\n        Self::new_base(\n            match &*lowercase_tag {\n                \"input\" => VTagInner::Input(Default::default()),\n                \"textarea\" => VTagInner::Textarea(Default::default()),\n                _ => VTagInner::Other {\n                    tag,\n                    children: Default::default(),\n                },\n            },\n            Default::default(),\n            Default::default(),\n            Default::default(),\n            Default::default(),\n        )\n    }\n\n    /// Creates a new\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) [VTag]\n    /// instance.\n    ///\n    /// Unlike [VTag::new()], this sets all the public fields of [VTag] in one call. This allows the\n    /// compiler to inline property and child list construction in the `html!` macro. This enables\n    /// higher instruction parallelism by reducing data dependency and avoids `memcpy` of Vtag\n    /// fields.\n    #[doc(hidden)]\n    #[allow(clippy::too_many_arguments)]\n    pub fn __new_input(\n        value: Option<AttrValue>,\n        checked: Option<bool>,\n        node_ref: NodeRef,\n        key: Option<Key>,\n        // at the bottom for more readable macro-expanded code\n        attributes: Attributes,\n        listeners: Listeners,\n    ) -> Self {\n        VTag::new_base(\n            VTagInner::Input(InputFields::new(\n                value,\n                // In HTML node `checked` attribute sets `defaultChecked` parameter,\n                // but we use own field to control real `checked` parameter\n                checked,\n            )),\n            node_ref,\n            key,\n            attributes,\n            listeners,\n        )\n    }\n\n    /// Creates a new\n    /// [TextArea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) [VTag]\n    /// instance.\n    ///\n    /// Unlike [VTag::new()], this sets all the public fields of [VTag] in one call. This allows the\n    /// compiler to inline property and child list construction in the `html!` macro. This enables\n    /// higher instruction parallelism by reducing data dependency and avoids `memcpy` of Vtag\n    /// fields.\n    #[doc(hidden)]\n    #[allow(clippy::too_many_arguments)]\n    pub fn __new_textarea(\n        value: Option<AttrValue>,\n        defaultvalue: Option<AttrValue>,\n        node_ref: NodeRef,\n        key: Option<Key>,\n        // at the bottom for more readable macro-expanded code\n        attributes: Attributes,\n        listeners: Listeners,\n    ) -> Self {\n        VTag::new_base(\n            VTagInner::Textarea(TextareaFields {\n                value: Value::new(value),\n                defaultvalue,\n            }),\n            node_ref,\n            key,\n            attributes,\n            listeners,\n        )\n    }\n\n    /// Creates a new [VTag] instance with `tag` name (cannot be changed later in DOM).\n    ///\n    /// Unlike [VTag::new()], this sets all the public fields of [VTag] in one call. This allows the\n    /// compiler to inline property and child list construction in the `html!` macro. This enables\n    /// higher instruction parallelism by reducing data dependency and avoids `memcpy` of Vtag\n    /// fields.\n    #[doc(hidden)]\n    #[allow(clippy::too_many_arguments)]\n    pub fn __new_other(\n        tag: AttrValue,\n        node_ref: NodeRef,\n        key: Option<Key>,\n        // at the bottom for more readable macro-expanded code\n        attributes: Attributes,\n        listeners: Listeners,\n        children: VNode,\n    ) -> Self {\n        VTag::new_base(\n            VTagInner::Other { tag, children },\n            node_ref,\n            key,\n            attributes,\n            listeners,\n        )\n    }\n\n    /// Constructs a [VTag] from [VTagInner] and fields common to all [VTag] kinds\n    #[inline]\n    #[allow(clippy::too_many_arguments)]\n    fn new_base(\n        inner: VTagInner,\n        node_ref: NodeRef,\n        key: Option<Key>,\n        attributes: Attributes,\n        listeners: Listeners,\n    ) -> Self {\n        VTag {\n            inner,\n            attributes,\n            listeners,\n            node_ref,\n            key,\n        }\n    }\n\n    /// Returns tag of an [Element](web_sys::Element). In HTML tags are always uppercase.\n    pub fn tag(&self) -> &str {\n        match &self.inner {\n            VTagInner::Input { .. } => \"input\",\n            VTagInner::Textarea { .. } => \"textarea\",\n            VTagInner::Other { tag, .. } => tag.as_ref(),\n        }\n    }\n\n    /// Add [VNode] child.\n    pub fn add_child(&mut self, child: VNode) {\n        if let VTagInner::Other { children, .. } = &mut self.inner {\n            children.to_vlist_mut().add_child(child)\n        }\n    }\n\n    /// Add multiple [VNode] children.\n    pub fn add_children(&mut self, children: impl IntoIterator<Item = VNode>) {\n        if let VTagInner::Other { children: dst, .. } = &mut self.inner {\n            dst.to_vlist_mut().add_children(children)\n        }\n    }\n\n    /// Returns a reference to the children of this [VTag], if the node can have\n    /// children\n    pub fn children(&self) -> Option<&VNode> {\n        match &self.inner {\n            VTagInner::Other { children, .. } => Some(children),\n            _ => None,\n        }\n    }\n\n    /// Returns a mutable reference to the children of this [VTag], if the node can have\n    /// children\n    pub fn children_mut(&mut self) -> Option<&mut VNode> {\n        match &mut self.inner {\n            VTagInner::Other { children, .. } => Some(children),\n            _ => None,\n        }\n    }\n\n    /// Returns the children of this [VTag], if the node can have\n    /// children\n    pub fn into_children(self) -> Option<VNode> {\n        match self.inner {\n            VTagInner::Other { children, .. } => Some(children),\n            _ => None,\n        }\n    }\n\n    /// Returns the `value` of an\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) or\n    /// [TextArea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)\n    pub fn value(&self) -> Option<&AttrValue> {\n        match &self.inner {\n            VTagInner::Input(f) => f.as_ref(),\n            VTagInner::Textarea(TextareaFields { value, .. }) => value.as_ref(),\n            VTagInner::Other { .. } => None,\n        }\n    }\n\n    /// Sets `value` for an\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) or\n    /// [TextArea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)\n    pub fn set_value(&mut self, value: impl IntoPropValue<Option<AttrValue>>) {\n        match &mut self.inner {\n            VTagInner::Input(f) => {\n                f.set(value.into_prop_value());\n            }\n            VTagInner::Textarea(TextareaFields { value: dst, .. }) => {\n                dst.set(value.into_prop_value());\n            }\n            VTagInner::Other { .. } => (),\n        }\n    }\n\n    /// Returns `checked` property of an\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).\n    /// (Does not affect the value of the node's attribute).\n    pub fn checked(&self) -> Option<bool> {\n        match &self.inner {\n            VTagInner::Input(f) => f.checked,\n            _ => None,\n        }\n    }\n\n    /// Sets `checked` property of an\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).\n    /// (Does not affect the value of the node's attribute).\n    pub fn set_checked(&mut self, value: bool) {\n        if let VTagInner::Input(f) = &mut self.inner {\n            f.checked = Some(value);\n        }\n    }\n\n    /// Keeps the current value of the `checked` property of an\n    /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).\n    /// (Does not affect the value of the node's attribute).\n    pub fn preserve_checked(&mut self) {\n        if let VTagInner::Input(f) = &mut self.inner {\n            f.checked = None;\n        }\n    }\n\n    /// Adds a key-value pair to attributes\n    ///\n    /// Not every attribute works when it set as an attribute. We use workarounds for:\n    /// `value` and `checked`.\n    pub fn add_attribute(&mut self, key: &'static str, value: impl Into<AttrValue>) {\n        self.attributes.get_mut_index_map().insert(\n            AttrValue::Static(key),\n            AttributeOrProperty::Attribute(value.into()),\n        );\n    }\n\n    /// Set the given key as property on the element\n    ///\n    /// [`js_sys::Reflect`] is used for setting properties.\n    pub fn add_property(&mut self, key: &'static str, value: impl Into<JsValue>) {\n        self.attributes.get_mut_index_map().insert(\n            AttrValue::Static(key),\n            AttributeOrProperty::Property(value.into()),\n        );\n    }\n\n    /// Sets attributes to a virtual node.\n    ///\n    /// Not every attribute works when it set as an attribute. We use workarounds for:\n    /// `value` and `checked`.\n    pub fn set_attributes(&mut self, attrs: impl Into<Attributes>) {\n        self.attributes = attrs.into();\n    }\n\n    #[doc(hidden)]\n    pub fn __macro_push_attr(&mut self, key: &'static str, value: impl IntoPropValue<AttrValue>) {\n        self.attributes.get_mut_index_map().insert(\n            AttrValue::from(key),\n            AttributeOrProperty::Attribute(value.into_prop_value()),\n        );\n    }\n\n    /// Add event listener on the [VTag]'s  [Element](web_sys::Element).\n    /// Returns `true` if the listener has been added, `false` otherwise.\n    pub fn add_listener(&mut self, listener: Rc<dyn Listener>) -> bool {\n        match &mut self.listeners {\n            Listeners::None => {\n                self.set_listeners([Some(listener)].into());\n                true\n            }\n            Listeners::Pending(listeners) => {\n                let mut listeners = mem::take(listeners).into_vec();\n                listeners.push(Some(listener));\n\n                self.set_listeners(listeners.into());\n                true\n            }\n        }\n    }\n\n    /// Set event listeners on the [VTag]'s  [Element](web_sys::Element)\n    pub fn set_listeners(&mut self, listeners: Box<[Option<Rc<dyn Listener>>]>) {\n        self.listeners = Listeners::Pending(listeners);\n    }\n}\n\nimpl PartialEq for VTag {\n    fn eq(&self, other: &VTag) -> bool {\n        use VTagInner::*;\n\n        (match (&self.inner, &other.inner) {\n            (Input(l), Input(r)) => l == r,\n            (Textarea (TextareaFields{ value: value_l, .. }), Textarea (TextareaFields{ value: value_r, .. })) => value_l == value_r,\n            (Other { tag: tag_l, .. }, Other { tag: tag_r, .. }) => tag_l == tag_r,\n            _ => false,\n        }) && self.listeners.eq(&other.listeners)\n            && self.attributes == other.attributes\n            // Diff children last, as recursion is the most expensive\n            && match (&self.inner, &other.inner) {\n                (Other { children: ch_l, .. }, Other { children: ch_r, .. }) => ch_l == ch_r,\n                _ => true,\n            }\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n    use std::fmt::Write;\n\n    use super::*;\n    use crate::feat_ssr::VTagKind;\n    use crate::html::AnyScope;\n    use crate::platform::fmt::BufWriter;\n    use crate::virtual_dom::VText;\n\n    // Elements that cannot have any child elements.\n    static VOID_ELEMENTS: &[&str; 15] = &[\n        \"area\", \"base\", \"br\", \"col\", \"embed\", \"hr\", \"img\", \"input\", \"link\", \"meta\", \"param\",\n        \"source\", \"track\", \"wbr\", \"textarea\",\n    ];\n\n    impl VTag {\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            parent_scope: &AnyScope,\n            hydratable: bool,\n        ) {\n            let _ = w.write_str(\"<\");\n            let _ = w.write_str(self.tag());\n\n            let write_attr = |w: &mut BufWriter, name: &str, val: Option<&str>| {\n                let _ = w.write_str(\" \");\n                let _ = w.write_str(name);\n\n                if let Some(m) = val {\n                    let _ = w.write_str(\"=\\\"\");\n                    let _ = w.write_str(&html_escape::encode_double_quoted_attribute(m));\n                    let _ = w.write_str(\"\\\"\");\n                }\n            };\n\n            if let VTagInner::Input(InputFields { value, checked }) = &self.inner {\n                if let Some(value) = value.as_deref() {\n                    write_attr(w, \"value\", Some(value));\n                }\n\n                // Setting is as an attribute sets the `defaultChecked` property. Only emit this\n                // if it's explicitly set to checked.\n                if *checked == Some(true) {\n                    write_attr(w, \"checked\", None);\n                }\n            }\n\n            for (k, v) in self.attributes.iter() {\n                write_attr(w, k, Some(v));\n            }\n\n            let _ = w.write_str(\">\");\n\n            match &self.inner {\n                VTagInner::Input(_) => {}\n                VTagInner::Textarea(TextareaFields {\n                    value,\n                    defaultvalue,\n                }) => {\n                    if let Some(def) = value.as_ref().or(defaultvalue.as_ref()) {\n                        VText::new(def.clone())\n                            .render_into_stream(w, parent_scope, hydratable, VTagKind::Other)\n                            .await;\n                    }\n\n                    let _ = w.write_str(\"</textarea>\");\n                }\n                VTagInner::Other { tag, children } => {\n                    let lowercase_tag = tag.to_ascii_lowercase();\n                    if !VOID_ELEMENTS.contains(&lowercase_tag.as_ref()) {\n                        children\n                            .render_into_stream(w, parent_scope, hydratable, tag.into())\n                            .await;\n\n                        let _ = w.write_str(\"</\");\n                        let _ = w.write_str(tag);\n                        let _ = w.write_str(\">\");\n                    } else {\n                        // We don't write children of void elements nor closing tags.\n                        debug_assert!(\n                            match children {\n                                VNode::VList(m) => m.is_empty(),\n                                _ => false,\n                            },\n                            \"{tag} cannot have any children!\"\n                        );\n                    }\n                }\n            }\n        }\n    }\n}\n\n#[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\n#[cfg(feature = \"ssr\")]\n#[cfg(test)]\nmod ssr_tests {\n    use tokio::test;\n\n    use crate::prelude::*;\n    use crate::LocalServerRenderer as ServerRenderer;\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_simple_tag() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <div></div> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, \"<div></div>\");\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_simple_tag_with_attr() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <div class=\"abc\"></div> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<div class=\"abc\"></div>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_simple_tag_with_content() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <div>{\"Hello!\"}</div> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<div>Hello!</div>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_simple_tag_with_nested_tag_and_input() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <div>{\"Hello!\"}<input value=\"abc\" type=\"text\" /></div> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<div>Hello!<input value=\"abc\" type=\"text\"></div>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_textarea() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <textarea value=\"teststring\" /> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<textarea>teststring</textarea>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_textarea_w_defaultvalue() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <textarea defaultvalue=\"teststring\" /> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<textarea>teststring</textarea>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_value_precedence_over_defaultvalue() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <textarea defaultvalue=\"defaultvalue\" value=\"value\" /> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<textarea>value</textarea>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_escaping_in_style_tag() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <style>{\"body > a {color: #cc0;}\"}</style> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<style>body > a {color: #cc0;}</style>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_escaping_in_script_tag() {\n        #[component]\n        fn Comp() -> Html {\n            html! { <script>{\"foo.bar = x < y;\"}</script> }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"<script>foo.bar = x < y;</script>\"#);\n    }\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_multiple_vtext_in_style_tag() {\n        #[component]\n        fn Comp() -> Html {\n            let one = \"html { background: black } \";\n            let two = \"body > a { color: white } \";\n            html! {\n                <style>\n                    {one}\n                    {two}\n                </style>\n            }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(\n            s,\n            r#\"<style>html { background: black } body > a { color: white } </style>\"#\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew/src/virtual_dom/vtext.rs",
    "content": "//! This module contains the implementation of a virtual text node `VText`.\n\nuse std::cmp::PartialEq;\n\nuse super::AttrValue;\nuse crate::html::ImplicitClone;\n\n/// A type for a virtual\n/// [`TextNode`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)\n/// representation.\n#[derive(Clone, ImplicitClone)]\npub struct VText {\n    /// Contains a text of the node.\n    pub text: AttrValue,\n}\n\nimpl VText {\n    /// Creates new virtual text node with a content.\n    pub fn new(text: impl Into<AttrValue>) -> Self {\n        VText { text: text.into() }\n    }\n}\n\nimpl std::fmt::Debug for VText {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"VText {{ text: \\\"{}\\\" }}\", self.text)\n    }\n}\n\nimpl PartialEq for VText {\n    fn eq(&self, other: &VText) -> bool {\n        self.text == other.text\n    }\n}\n\nimpl<T: ToString> From<T> for VText {\n    fn from(value: T) -> Self {\n        VText::new(value.to_string())\n    }\n}\n\n#[cfg(feature = \"ssr\")]\nmod feat_ssr {\n\n    use std::fmt::Write;\n\n    use super::*;\n    use crate::feat_ssr::VTagKind;\n    use crate::html::AnyScope;\n    use crate::platform::fmt::BufWriter;\n\n    impl VText {\n        pub(crate) async fn render_into_stream(\n            &self,\n            w: &mut BufWriter,\n            _parent_scope: &AnyScope,\n            _hydratable: bool,\n            parent_vtag_kind: VTagKind,\n        ) {\n            _ = w.write_str(&match parent_vtag_kind {\n                VTagKind::Style => html_escape::encode_style(&self.text),\n                VTagKind::Script => html_escape::encode_script(&self.text),\n                VTagKind::Other => html_escape::encode_text(&self.text),\n            })\n        }\n    }\n}\n\n#[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\n#[cfg(feature = \"ssr\")]\n#[cfg(test)]\nmod ssr_tests {\n    use tokio::test;\n\n    use crate::prelude::*;\n    use crate::LocalServerRenderer as ServerRenderer;\n\n    #[cfg_attr(not(target_os = \"wasi\"), test)]\n    #[cfg_attr(target_os = \"wasi\", test(flavor = \"current_thread\"))]\n    async fn test_simple_str() {\n        #[component]\n        fn Comp() -> Html {\n            html! { \"abc\" }\n        }\n\n        let s = ServerRenderer::<Comp>::new()\n            .hydratable(false)\n            .render()\n            .await;\n\n        assert_eq!(s, r#\"abc\"#);\n    }\n}\n"
  },
  {
    "path": "packages/yew/tests/common/mod.rs",
    "content": "#![allow(dead_code)]\n\npub fn obtain_result() -> String {\n    gloo::utils::document()\n        .get_element_by_id(\"result\")\n        .expect(\"No result found. Most likely, the application crashed and burned\")\n        .inner_html()\n}\n\npub fn obtain_result_by_id(id: &str) -> String {\n    gloo::utils::document()\n        .get_element_by_id(id)\n        .expect(\"No result found. Most likely, the application crashed and burned\")\n        .inner_html()\n}\n\npub fn output_element() -> web_sys::Element {\n    gloo::utils::document().get_element_by_id(\"output\").unwrap()\n}\n"
  },
  {
    "path": "packages/yew/tests/hydration.rs",
    "content": "#![cfg(feature = \"hydration\")]\n#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nuse std::ops::Range;\nuse std::rc::Rc;\nuse std::time::Duration;\n\nmod common;\n\nuse common::{obtain_result, obtain_result_by_id};\nuse wasm_bindgen::JsCast;\nuse wasm_bindgen_futures::spawn_local;\nuse wasm_bindgen_test::*;\nuse web_sys::{HtmlElement, HtmlTextAreaElement};\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew::suspense::{use_future, Suspension, SuspensionResult};\nuse yew::virtual_dom::VNode;\nuse yew::{component, scheduler, Renderer, ServerRenderer};\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n// If any of the assertions fail due to a modification to hydration logic, cargo will suggest the\n// expected result and you can copy it into the test to fix it.\n\n#[wasm_bindgen_test]\nasync fn hydration_works() {\n    #[component]\n    fn Comp() -> Html {\n        let ctr = use_state_eq(|| 0);\n\n        let onclick = {\n            let ctr = ctr.clone();\n\n            Callback::from(move |_| {\n                ctr.set(*ctr + 1);\n            })\n        };\n\n        html! {\n            <div>\n                {\"Counter: \"}{*ctr}\n                <button {onclick} class=\"increase\">{\"+1\"}</button>\n            </div>\n        }\n    }\n\n    #[component]\n    fn App() -> Html {\n        html! {\n            <div>\n                <Comp />\n            </div>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n\n    // no placeholders, hydration is successful.\n    assert_eq!(\n        result,\n        r#\"<div><div>Counter: 0<button class=\"increase\">+1</button></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".increase\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n\n    assert_eq!(\n        result,\n        r#\"<div><div>Counter: 1<button class=\"increase\">+1</button></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_with_raw() {\n    #[component(Content)]\n    fn content() -> Html {\n        let vnode = VNode::from_html_unchecked(\"<div><p>Hello World</p></div>\".into());\n\n        html! {\n            <div class=\"content-area\">\n                {vnode}\n            </div>\n        }\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        html! {\n            <div id=\"result\">\n                <Content />\n            </div>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    sleep(Duration::from_millis(10)).await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    let result = obtain_result();\n\n    // still hydrating, during hydration, the server rendered result is shown.\n    assert_eq!(\n        result.as_str(),\n        r#\"<!--<[hydration::hydration_with_raw::{{closure}}::Content]>--><div class=\"content-area\"><!--<#>--><div><p>Hello World</p></div><!--</#>--></div><!--</[hydration::hydration_with_raw::{{closure}}::Content]>-->\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n\n    // hydrated.\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div><p>Hello World</p></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_with_suspense() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Suspension,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            Self::new().into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        if sleep_state.s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(sleep_state.s.clone())\n        }\n    }\n\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let value = use_state(|| 0);\n\n        let on_increment = {\n            let value = value.clone();\n\n            Callback::from(move |_: MouseEvent| {\n                value.set(*value + 1);\n            })\n        };\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"actual-result\">{*value}</div>\n                <button class=\"increase\" onclick={on_increment}>{\"increase\"}</button>\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    sleep(Duration::from_millis(10)).await;\n\n    let result = obtain_result();\n\n    // still hydrating, during hydration, the server rendered result is shown.\n    assert_eq!(\n        result.as_str(),\n        r#\"<!--<[hydration::hydration_with_suspense::{{closure}}::Content]>--><div class=\"content-area\"><div class=\"actual-result\">0</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div><!--</[hydration::hydration_with_suspense::{{closure}}::Content]>-->\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n\n    // hydrated.\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">0</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".increase\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">1</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".take-a-break\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">1</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_with_suspense_not_suspended_at_start() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Option<Suspension>,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            Self { s: None }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s: Some(s) }.into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        let s = match sleep_state.s.clone() {\n            Some(m) => m,\n            None => return Ok(Rc::new(move || sleep_state.dispatch(()))),\n        };\n\n        if s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(s)\n        }\n    }\n\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let value = use_state(|| \"I am writing a long story...\".to_string());\n\n        let on_text_input = {\n            let value = value.clone();\n\n            Callback::from(move |e: InputEvent| {\n                let input: HtmlTextAreaElement = e.target_unchecked_into();\n\n                value.set(input.value());\n            })\n        };\n\n        let on_take_a_break = Callback::from(move |_| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <textarea value={value.to_string()} oninput={on_text_input}/>\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    sleep(Duration::from_millis(10)).await;\n\n    let result = obtain_result();\n\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><textarea>I am writing a long story...</textarea><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n    gloo::utils::document()\n        .query_selector(\".take-a-break\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><textarea>I am writing a long story...</textarea><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_nested_suspense_works() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Suspension,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            Self::new().into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        if sleep_state.s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(sleep_state.s.clone())\n        }\n    }\n\n    #[component(InnerContent)]\n    fn inner_content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"action-area\">\n                    <button class=\"take-a-break2\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let fallback = html! {<div>{\"wait...(inner)\"}</div>};\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n                <Suspense {fallback}>\n                    <InnerContent />\n                </Suspense>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...(outer)\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    // outer suspense is hydrating...\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<!--<[hydration::hydration_nested_suspense_works::{{closure}}::Content]>--><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><!--<[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--<[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--<?>--><!--<[hydration::hydration_nested_suspense_works::{{closure}}::InnerContent]>--><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div><!--</[hydration::hydration_nested_suspense_works::{{closure}}::InnerContent]>--><!--</?>--><!--</[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--</[yew::suspense::component::feat_csr_ssr::Suspense]>--></div><!--</[hydration::hydration_nested_suspense_works::{{closure}}::Content]>-->\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    // inner suspense is hydrating...\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><!--<[hydration::hydration_nested_suspense_works::{{closure}}::InnerContent]>--><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div><!--</[hydration::hydration_nested_suspense_works::{{closure}}::InnerContent]>--></div>\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    // hydrated.\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".take-a-break\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...(outer)</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".take-a-break2\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div>wait...(inner)</div></div>\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_node_ref_works() {\n    #[component(App)]\n    pub fn app() -> Html {\n        let size = use_state(|| 4);\n\n        let callback = {\n            let size = size.clone();\n            Callback::from(move |_| {\n                size.set(10);\n            })\n        };\n\n        html! {\n            <div onclick={callback}>\n                <List size={*size}/>\n            </div>\n        }\n    }\n\n    #[derive(Properties, PartialEq)]\n    struct ListProps {\n        size: u32,\n    }\n\n    #[component(Test1)]\n    fn test1() -> Html {\n        html! {\n            <span>{\"test\"}</span>\n        }\n    }\n    #[component(Test2)]\n    fn test2() -> Html {\n        html! {\n            <Test1/>\n        }\n    }\n\n    #[component(List)]\n    fn list(props: &ListProps) -> Html {\n        let elems = 0..props.size;\n\n        html! {\n            <>\n            { for elems.map(|_|\n                html! {\n                    <Test2/>\n                }\n            )}\n            </>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        r#\"<div><span>test</span><span>test</span><span>test</span><span>test</span></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\"span\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        r#\"<div><span>test</span><span>test</span><span>test</span><span>test</span><span>test</span><span>test</span><span>test</span><span>test</span><span>test</span><span>test</span></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_list_order_works() {\n    #[component(App)]\n    pub fn app() -> Html {\n        let elems = 0..10;\n\n        html! {\n            <>\n            { for elems.map(|number|\n                html! {\n                    <ToSuspendOrNot {number}/>\n                }\n            )}\n            </>\n        }\n    }\n\n    #[derive(Properties, PartialEq)]\n    struct NumberProps {\n        number: u32,\n    }\n\n    #[component(Number)]\n    fn number(props: &NumberProps) -> Html {\n        html! {\n            <div>{props.number.to_string()}</div>\n        }\n    }\n    #[component(SuspendedNumber)]\n    fn suspended_number(props: &NumberProps) -> HtmlResult {\n        use_suspend()?;\n        Ok(html! {\n            <div>{props.number.to_string()}</div>\n        })\n    }\n    #[component(ToSuspendOrNot)]\n    fn suspend_or_not(props: &NumberProps) -> Html {\n        let number = props.number;\n        html! {\n            <Suspense>\n                if number % 3 == 0 {\n                    <SuspendedNumber {number}/>\n                } else {\n                    <Number {number}/>\n                }\n            </Suspense>\n        }\n    }\n\n    #[hook]\n    pub fn use_suspend() -> SuspensionResult<()> {\n        use_future(|| async {})?;\n        Ok(())\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    // Wait until all suspended components becomes revealed.\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        // Until all components become revealed, there will be component markers.\n        // As long as there's no component markers all components have become unsuspended.\n        r#\"<div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_suspense_no_flickering() {\n    #[component(App)]\n    pub fn app() -> Html {\n        let fallback = html! { <h1>{\"Loading...\"}</h1> };\n        html! {\n            <Suspense {fallback}>\n                <Suspended/>\n            </Suspense>\n        }\n    }\n\n    #[derive(Properties, PartialEq, Clone)]\n    struct NumberProps {\n        number: u32,\n    }\n\n    #[component(SuspendedNumber)]\n    fn suspended_number(props: &NumberProps) -> HtmlResult {\n        use_suspend()?;\n\n        Ok(html! {\n            <Number ..{props.clone()}/>\n        })\n    }\n    #[component(Number)]\n    fn number(props: &NumberProps) -> Html {\n        html! {\n            <div>\n                {props.number.to_string()}\n            </div>\n        }\n    }\n\n    #[component(Suspended)]\n    fn suspended() -> HtmlResult {\n        use_suspend()?;\n\n        Ok(html! {\n            { for (0..10).map(|number|\n                html! {\n                    <SuspendedNumber {number}/>\n                }\n            )}\n        })\n    }\n\n    #[hook]\n    pub fn use_suspend() -> SuspensionResult<()> {\n        use_future(|| async {\n            yew::platform::time::sleep(std::time::Duration::from_millis(200)).await;\n        })?;\n        Ok(())\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    // Wait until all suspended components becomes revealed.\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        // outer still suspended.\n        r#\"<!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>0</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>1</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>2</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>3</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>4</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>5</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>6</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>7</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>8</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>9</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>-->\"#\n    );\n    sleep(Duration::from_millis(103)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        r#\"<!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>0</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>1</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>2</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>3</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>4</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>5</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>6</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>7</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>8</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>9</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>-->\"#\n    );\n    sleep(Duration::from_millis(103)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        r#\"<!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>0</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>1</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>2</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>3</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>4</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>5</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>6</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>7</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>8</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>9</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>-->\"#\n    );\n    sleep(Duration::from_millis(103)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        // outer revealed, inner still suspended, outer remains.\n        r#\"<!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>0</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>1</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>2</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>3</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>4</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>5</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>6</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>7</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>8</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--<[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><div>9</div><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Number]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::SuspendedNumber]>--><!--</[hydration::hydration_suspense_no_flickering::{{closure}}::Suspended]>-->\"#\n    );\n\n    sleep(Duration::from_millis(103)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        // inner revealed.\n        r#\"<div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_order_issue_nested_suspense() {\n    #[component(App)]\n    pub fn app() -> Html {\n        let elems = (0..10).map(|number: u32| {\n            html! {\n                <ToSuspendOrNot {number} key={number} />\n            }\n        });\n\n        html! {\n            <Suspense>\n                { for elems }\n            </Suspense>\n        }\n    }\n\n    #[derive(Properties, PartialEq)]\n    struct NumberProps {\n        number: u32,\n    }\n\n    #[component(Number)]\n    fn number(props: &NumberProps) -> Html {\n        html! {\n            <div>{props.number.to_string()}</div>\n        }\n    }\n\n    #[component(SuspendedNumber)]\n    fn suspended_number(props: &NumberProps) -> HtmlResult {\n        use_suspend()?;\n        Ok(html! {\n            <div>{props.number.to_string()}</div>\n        })\n    }\n\n    #[component(ToSuspendOrNot)]\n    fn suspend_or_not(props: &NumberProps) -> HtmlResult {\n        let number = props.number;\n        Ok(html! {\n            if number % 3 == 0 {\n                <Suspense>\n                    <SuspendedNumber {number} />\n                </Suspense>\n            } else {\n                <Number {number} />\n            }\n        })\n    }\n\n    #[hook]\n    pub fn use_suspend() -> SuspensionResult<()> {\n        use_future(|| async {})?;\n\n        Ok(())\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    // Wait until all suspended components becomes revealed.\n    scheduler::flush().await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(\n        result.as_str(),\n        // Until all components become revealed, there will be component markers.\n        // As long as there's no component markers all components have become unsuspended.\n        r#\"<div>0</div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div><div>9</div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_props_blocked_until_hydrated() {\n    #[component(App)]\n    pub fn app() -> Html {\n        let range = use_state(|| 0u32..2);\n        {\n            let range = range.clone();\n            use_effect_with((), move |_| {\n                range.set(0..3);\n                || ()\n            });\n        }\n\n        html! {\n            <Suspense>\n                <ToSuspend range={(*range).clone()}/>\n            </Suspense>\n        }\n    }\n\n    #[derive(Properties, PartialEq)]\n    struct ToSuspendProps {\n        range: Range<u32>,\n    }\n\n    #[component(ToSuspend)]\n    fn to_suspend(ToSuspendProps { range }: &ToSuspendProps) -> HtmlResult {\n        use_suspend(Duration::from_millis(100))?;\n        Ok(html! {\n            { for range.clone().map(|i|\n                html!{ <div key={i}>{i}</div> }\n            )}\n        })\n    }\n\n    #[hook]\n    pub fn use_suspend(_dur: Duration) -> SuspensionResult<()> {\n        yew::suspense::use_future(|| async move {\n            sleep(_dur).await;\n        })?;\n\n        Ok(())\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    let output_element = gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap();\n\n    output_element.set_inner_html(&s);\n\n    Renderer::<App>::with_root(output_element).hydrate();\n    sleep(Duration::from_millis(150)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(result.as_str(), r#\"<div>0</div><div>1</div><div>2</div>\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn hydrate_empty() {\n    #[component]\n    fn Updating() -> Html {\n        let trigger = use_state(|| false);\n        {\n            let trigger = trigger.clone();\n            use_effect_with((), move |_| {\n                trigger.set(true);\n                || {}\n            });\n        }\n        if *trigger {\n            html! { <div>{\"after\"}</div> }\n        } else {\n            html! { <div>{\"before\"}</div> }\n        }\n    }\n    #[component]\n    fn Empty() -> Html {\n        html! { <></> }\n    }\n    #[component]\n    fn App() -> Html {\n        html! {\n            <>\n                <Updating />\n                <Empty />\n                <Updating />\n            </>\n        }\n    }\n    let s = ServerRenderer::<App>::new().render().await;\n\n    let output_element = gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap();\n\n    output_element.set_inner_html(&s);\n\n    Renderer::<App>::with_root(output_element).hydrate();\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(result.as_str(), r#\"<div>after</div><div>after</div>\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn hydrate_flicker() {\n    // This components renders the same on the server and client during the first render,\n    // but then immediately changes the order of keyed elements in the next render.\n    // This should not lead to any hydration failures\n    #[derive(Properties, PartialEq)]\n    struct InnerCompProps {\n        text: String,\n    }\n    #[component]\n    fn InnerComp(InnerCompProps { text }: &InnerCompProps) -> Html {\n        html! { <p>{text.clone()}</p> }\n    }\n    #[component]\n    fn Flickering() -> Html {\n        let trigger = use_state(|| false);\n        let is_first = !*trigger;\n        if is_first {\n            trigger.set(true);\n            html! {\n                <>\n                    <InnerComp key=\"1\" text=\"1\" />\n                    <InnerComp key=\"2\" text=\"2\" />\n                </>\n            }\n        } else {\n            html! {\n                <>\n                    <InnerComp key=\"2\" text=\"2\" />\n                    <InnerComp key=\"1\" text=\"1\" />\n                </>\n            }\n        }\n    }\n    let s = ServerRenderer::<Flickering>::new().render().await;\n    let output_element = gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap();\n\n    output_element.set_inner_html(&s);\n\n    Renderer::<Flickering>::with_root(output_element).hydrate();\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result_by_id(\"output\");\n    assert_eq!(result.as_str(), r#\"<p>2</p><p>1</p>\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_with_camelcase_svg_elements() {\n    #[function_component]\n    fn SvgWithCamelCase() -> Html {\n        html! {\n            <svg width=\"100\" height=\"100\">\n                <defs>\n                    <@{\"linearGradient\"} id=\"gradient1\">\n                        <stop offset=\"0%\" stop-color=\"red\" />\n                        <stop offset=\"100%\" stop-color=\"blue\" />\n                    </@>\n                    <@{\"radialGradient\"} id=\"gradient2\">\n                        <stop offset=\"0%\" stop-color=\"yellow\" />\n                        <stop offset=\"100%\" stop-color=\"green\" />\n                    </@>\n                    <@{\"clipPath\"} id=\"clip1\">\n                        <circle cx=\"50\" cy=\"50\" r=\"40\" />\n                    </@>\n                </defs>\n                <rect x=\"10\" y=\"10\" width=\"80\" height=\"80\" fill=\"url(#gradient1)\" />\n                <circle cx=\"50\" cy=\"50\" r=\"30\" fill=\"url(#gradient2)\" clip-path=\"url(#clip1)\" />\n                <@{\"feDropShadow\"} dx=\"2\" dy=\"2\" stdDeviation=\"2\" />\n            </svg>\n        }\n    }\n\n    #[function_component]\n    fn App() -> Html {\n        let counter = use_state(|| 0);\n        let onclick = {\n            let counter = counter.clone();\n            Callback::from(move |_| counter.set(*counter + 1))\n        };\n\n        html! {\n            <div id=\"result\">\n                <div class=\"counter\">{\"Count: \"}{*counter}</div>\n                <button {onclick} class=\"increment\">{\"Increment\"}</button>\n                <SvgWithCamelCase />\n            </div>\n        }\n    }\n\n    // Server render\n    let s = ServerRenderer::<App>::new().render().await;\n\n    // Set HTML\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    // Hydrate - this should not panic\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    sleep(Duration::from_millis(10)).await;\n\n    // Verify the SVG elements are present and properly cased\n    let svg = gloo::utils::document()\n        .query_selector(\"svg\")\n        .unwrap()\n        .unwrap();\n\n    let linear_gradient = svg.query_selector(\"linearGradient\").unwrap().unwrap();\n    assert_eq!(linear_gradient.tag_name(), \"linearGradient\");\n\n    let radial_gradient = svg.query_selector(\"radialGradient\").unwrap().unwrap();\n    assert_eq!(radial_gradient.tag_name(), \"radialGradient\");\n\n    let clip_path = svg.query_selector(\"clipPath\").unwrap().unwrap();\n    assert_eq!(clip_path.tag_name(), \"clipPath\");\n\n    // Test interactivity still works after hydration\n    gloo::utils::document()\n        .query_selector(\".increment\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n\n    let counter_text = gloo::utils::document()\n        .query_selector(\".counter\")\n        .unwrap()\n        .unwrap()\n        .text_content()\n        .unwrap();\n\n    assert_eq!(counter_text, \"Count: 1\");\n}\n\n#[wasm_bindgen_test]\nasync fn hydration_suspended_child_does_not_trap_sibling_slot() {\n    #[hook]\n    fn use_suspend() -> SuspensionResult<()> {\n        use_future(|| async {})?;\n        Ok(())\n    }\n\n    #[component(SuspendingChild)]\n    fn suspending_child() -> HtmlResult {\n        use_suspend()?;\n        Ok(html! { <div class=\"suspended\">{\"child\"}</div> })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let trigger = use_state(|| false);\n        {\n            let trigger = trigger.clone();\n            use_effect_with((), move |_| {\n                trigger.set(true);\n            });\n        }\n\n        html! {\n            <div id=\"result\">\n                <Suspense fallback={html!{<div>{\"Loading...\"}</div>}}>\n                    if *trigger {\n                        <p class=\"new-sibling\">{\"new sibling\"}</p>\n                    }\n                    <SuspendingChild />\n                </Suspense>\n            </div>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    scheduler::flush().await;\n\n    let result = obtain_result();\n\n    assert_eq!(\n        result.as_str(),\n        r#\"<p class=\"new-sibling\">new sibling</p><div class=\"suspended\">child</div>\"#,\n    );\n}\n"
  },
  {
    "path": "packages/yew/tests/layout.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\nuse std::time::Duration;\n\nuse common::obtain_result;\nuse wasm_bindgen_futures::spawn_local;\nuse wasm_bindgen_test::*;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\n\n#[wasm_bindgen_test]\nasync fn change_nested_after_append() {\n    #[component]\n    fn Nested() -> Html {\n        let delayed_trigger = use_state(|| true);\n\n        {\n            let delayed_trigger = delayed_trigger.clone();\n            use_effect_with((), move |_| {\n                spawn_local(async move {\n                    sleep(Duration::from_millis(50)).await;\n                    delayed_trigger.set(false);\n                });\n                || {}\n            });\n        }\n\n        if *delayed_trigger {\n            html! { <div>{\"failure\"}</div> }\n        } else {\n            html! { <><i></i><span id=\"result\">{\"success\"}</span></> }\n        }\n    }\n\n    #[component]\n    fn Top() -> Html {\n        html! { <Nested /> }\n    }\n\n    #[component]\n    fn App() -> Html {\n        let show_bottom = use_state_eq(|| false);\n\n        {\n            let show_bottom = show_bottom.clone();\n\n            use_effect_with((), move |_| {\n                show_bottom.set(true);\n                || {}\n            });\n        }\n\n        html! {\n            <>\n                <Top />\n                if *show_bottom {\n                    <div>{\"<div>Bottom</div>\"}</div>\n                }\n            </>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(100)).await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"success\");\n}\n"
  },
  {
    "path": "packages/yew/tests/mod.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nuse common::obtain_result;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn props_are_passed() {\n    #[derive(Properties, Clone, PartialEq)]\n    struct PropsPassedFunctionProps {\n        value: String,\n    }\n\n    #[component]\n    fn PropsComponent(props: &PropsPassedFunctionProps) -> Html {\n        assert_eq!(&props.value, \"props\");\n        html! {\n            <div id=\"result\">\n                {\"done\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<PropsComponent>::with_root_and_props(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n        PropsPassedFunctionProps {\n            value: \"props\".to_string(),\n        },\n    )\n    .render();\n\n    scheduler::flush().await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"done\");\n}\n"
  },
  {
    "path": "packages/yew/tests/raw_html.rs",
    "content": "mod common;\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\nuse wasm_bindgen::JsCast;\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\nuse wasm_bindgen_test::wasm_bindgen_test as test;\nuse yew::prelude::*;\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n#[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\nuse tokio::test;\n\nmacro_rules! create_test {\n    ($name:ident, $html:expr) => {\n        create_test!($name, $html, $html);\n    };\n    ($name:ident, $raw:expr, $expected:expr) => {\n        #[test]\n        async fn $name() {\n            #[component]\n            fn App() -> Html {\n                let raw = Html::from_html_unchecked(AttrValue::from($raw));\n                html! {\n                    <div id=\"raw-container\">\n                        {raw}\n                    </div>\n                }\n            }\n\n            #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n            {\n                use std::time::Duration;\n\n                use yew::platform::time::sleep;\n\n                yew::Renderer::<App>::with_root(\n                    gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n                )\n                .render();\n\n                // wait for render to finish\n                sleep(Duration::from_millis(100)).await;\n\n                let e = gloo::utils::document()\n                    .get_element_by_id(\"raw-container\")\n                    .unwrap();\n                assert_eq!(e.inner_html(), $expected);\n            }\n            #[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\n            {\n                let actual = yew::LocalServerRenderer::<App>::new()\n                    .hydratable(false)\n                    .render()\n                    .await;\n                assert_eq!(\n                    actual,\n                    format!(r#\"<div id=\"raw-container\">{}</div>\"#, $expected)\n                );\n            }\n        }\n    };\n}\n\ncreate_test!(empty_string, \"\");\ncreate_test!(one_node, \"<span>text</span>\");\ncreate_test!(\n    one_but_nested_node,\n    r#\"<p>one <a href=\"https://yew.rs\">link</a> more paragraph</p>\"#\n);\ncreate_test!(\n    multi_node,\n    r#\"<p>paragraph</p><a href=\"https://yew.rs\">link</a>\"#\n);\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\nmacro_rules! create_update_html_test {\n    ($name:ident, $initial:expr, $updated:expr) => {\n        #[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n        #[test]\n        async fn $name() {\n            #[component]\n            fn App() -> Html {\n                let raw_html = use_state(|| ($initial));\n                let onclick = {\n                    let raw_html = raw_html.clone();\n                    move |_| raw_html.set($updated)\n                };\n                let raw = Html::from_html_unchecked(AttrValue::from(*raw_html));\n                html! {\n                    <>\n                        <div id=\"raw-container\">\n                            {raw}\n                        </div>\n                        <button id=\"click-me-btn\" {onclick}>{\"Click me\"}</button>\n                    </>\n                }\n            }\n            use std::time::Duration;\n\n            use yew::platform::time::sleep;\n\n            yew::Renderer::<App>::with_root(\n                gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n            )\n            .render();\n\n            // wait for render to finish\n            sleep(Duration::from_millis(100)).await;\n\n            let e = gloo::utils::document()\n                .get_element_by_id(\"raw-container\")\n                .unwrap();\n            assert_eq!(e.inner_html(), $initial);\n\n            gloo::utils::document()\n                .get_element_by_id(\"click-me-btn\")\n                .unwrap()\n                .unchecked_into::<web_sys::HtmlButtonElement>()\n                .click();\n\n            sleep(Duration::from_millis(100)).await;\n\n            let e = gloo::utils::document()\n                .get_element_by_id(\"raw-container\")\n                .unwrap();\n            assert_eq!(e.inner_html(), $updated);\n        }\n    };\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\ncreate_update_html_test!(\n    set_new_html_string,\n    \"<span>first</span>\",\n    \"<span>second</span>\"\n);\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\ncreate_update_html_test!(\n    set_new_html_string_multiple_children,\n    \"<span>first</span><span>second</span>\",\n    \"<span>second</span>\"\n);\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\ncreate_update_html_test!(\n    clear_html_string_multiple_children,\n    \"<span>first</span><span>second</span>\",\n    \"\"\n);\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\ncreate_update_html_test!(\n    nothing_changes,\n    \"<span>first</span><span>second</span>\",\n    \"<span>first</span><span>second</span>\"\n);\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[test]\nasync fn change_vnode_types_from_other_to_vraw() {\n    #[component]\n    fn App() -> Html {\n        let node = use_state(|| html!(\"text\"));\n        let onclick = {\n            let node = node.clone();\n            move |_| {\n                node.set(Html::from_html_unchecked(AttrValue::from(\n                    \"<span>second</span>\",\n                )))\n            }\n        };\n        html! {\n            <>\n                <div id=\"raw-container\">\n                    {(*node).clone()}\n                </div>\n                <button id=\"click-me-btn\" {onclick}>{\"Click me\"}</button>\n            </>\n        }\n    }\n    use std::time::Duration;\n\n    use yew::platform::time::sleep;\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    // wait for render to finish\n    sleep(Duration::from_millis(100)).await;\n\n    let e = gloo::utils::document()\n        .get_element_by_id(\"raw-container\")\n        .unwrap();\n    assert_eq!(e.inner_html(), \"text\");\n\n    gloo::utils::document()\n        .get_element_by_id(\"click-me-btn\")\n        .unwrap()\n        .unchecked_into::<web_sys::HtmlButtonElement>()\n        .click();\n\n    sleep(Duration::from_millis(100)).await;\n\n    let e = gloo::utils::document()\n        .get_element_by_id(\"raw-container\")\n        .unwrap();\n    assert_eq!(e.inner_html(), \"<span>second</span>\");\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#[test]\nasync fn change_vnode_types_from_vraw_to_other() {\n    #[component]\n    fn App() -> Html {\n        let node = use_state(|| Html::from_html_unchecked(AttrValue::from(\"<span>second</span>\")));\n        let onclick = {\n            let node = node.clone();\n            move |_| node.set(html!(\"text\"))\n        };\n        html! {\n            <>\n                <div id=\"raw-container\">\n                    {(*node).clone()}\n                </div>\n                <button id=\"click-me-btn\" {onclick}>{\"Click me\"}</button>\n            </>\n        }\n    }\n    use std::time::Duration;\n\n    use yew::platform::time::sleep;\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    // wait for render to finish\n    sleep(Duration::from_millis(100)).await;\n\n    let e = gloo::utils::document()\n        .get_element_by_id(\"raw-container\")\n        .unwrap();\n    assert_eq!(e.inner_html(), \"<span>second</span>\");\n\n    gloo::utils::document()\n        .get_element_by_id(\"click-me-btn\")\n        .unwrap()\n        .unchecked_into::<web_sys::HtmlButtonElement>()\n        .click();\n\n    sleep(Duration::from_millis(100)).await;\n\n    let e = gloo::utils::document()\n        .get_element_by_id(\"raw-container\")\n        .unwrap();\n    assert_eq!(e.inner_html(), \"text\");\n}\n"
  },
  {
    "path": "packages/yew/tests/suspense.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\nuse std::time::Duration;\n\nuse common::obtain_result;\nuse wasm_bindgen::JsCast;\nuse wasm_bindgen_test::*;\nuse web_sys::{HtmlElement, HtmlTextAreaElement};\nuse yew::platform::spawn_local;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew::suspense::{use_future, use_future_with, Suspension, SuspensionResult};\nuse yew::{scheduler, UseStateHandle};\n\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn suspense_works() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Suspension,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            Self::new().into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        if sleep_state.s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(sleep_state.s.clone())\n        }\n    }\n\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let value = use_state(|| 0);\n\n        let on_increment = {\n            let value = value.clone();\n\n            Callback::from(move |_: MouseEvent| {\n                value.set(*value + 1);\n            })\n        };\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"actual-result\">{*value}</div>\n                <button class=\"increase\" onclick={on_increment}>{\"increase\"}</button>\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">0</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n\n    sleep(Duration::from_millis(10)).await;\n\n    gloo::utils::document()\n        .query_selector(\".increase\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    scheduler::flush().await;\n\n    gloo::utils::document()\n        .query_selector(\".increase\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(1)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">2</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".take-a-break\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">2</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn suspense_not_suspended_at_start() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Option<Suspension>,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            Self { s: None }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s: Some(s) }.into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        let s = match sleep_state.s.clone() {\n            Some(m) => m,\n            None => return Ok(Rc::new(move || sleep_state.dispatch(()))),\n        };\n\n        if s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(s)\n        }\n    }\n\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let value = use_state(|| \"I am writing a long story...\".to_string());\n\n        let on_text_input = {\n            let value = value.clone();\n\n            Callback::from(move |e: InputEvent| {\n                let input: HtmlTextAreaElement = e.target_unchecked_into();\n\n                value.set(input.value());\n            })\n        };\n\n        let on_take_a_break = Callback::from(move |_| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <textarea value={value.to_string()} oninput={on_text_input}/>\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(10)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><textarea></textarea><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n    gloo::utils::document()\n        .query_selector(\".take-a-break\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><textarea></textarea><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn suspense_nested_suspense_works() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Suspension,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            Self::new().into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        if sleep_state.s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(sleep_state.s.clone())\n        }\n    }\n\n    #[component(InnerContent)]\n    fn inner_content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"action-area\">\n                    <button class=\"take-a-break2\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let resleep = use_sleep()?;\n\n        let fallback = html! {<div>{\"wait...(inner)\"}</div>};\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n                <Suspense {fallback}>\n                    <InnerContent />\n                </Suspense>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...(outer)\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...(outer)</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div>wait...(inner)</div></div>\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div></div>\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\".take-a-break2\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div>wait...(inner)</div></div>\"#\n    );\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div><div class=\"content-area\"><div class=\"action-area\"><button class=\"take-a-break2\">Take a break!</button></div></div></div>\"#\n    );\n}\n\n#[wasm_bindgen_test]\nasync fn effects_not_run_when_suspended() {\n    #[derive(PartialEq)]\n    pub struct SleepState {\n        s: Suspension,\n    }\n\n    impl SleepState {\n        fn new() -> Self {\n            let (s, handle) = Suspension::new();\n\n            spawn_local(async move {\n                sleep(Duration::from_millis(50)).await;\n\n                handle.resume();\n            });\n\n            Self { s }\n        }\n    }\n\n    impl Reducible for SleepState {\n        type Action = ();\n\n        fn reduce(self: Rc<Self>, _action: Self::Action) -> Rc<Self> {\n            Self::new().into()\n        }\n    }\n\n    #[hook]\n    pub fn use_sleep() -> SuspensionResult<Rc<dyn Fn()>> {\n        let sleep_state = use_reducer(SleepState::new);\n\n        if sleep_state.s.resumed() {\n            Ok(Rc::new(move || sleep_state.dispatch(())))\n        } else {\n            Err(sleep_state.s.clone())\n        }\n    }\n\n    #[derive(Properties, Clone)]\n    struct Props {\n        counter: Rc<RefCell<u64>>,\n    }\n\n    impl PartialEq for Props {\n        fn eq(&self, _rhs: &Self) -> bool {\n            true\n        }\n    }\n\n    #[component(Content)]\n    fn content(props: &Props) -> HtmlResult {\n        {\n            let counter = props.counter.clone();\n\n            use_effect(move || {\n                let mut counter = counter.borrow_mut();\n\n                *counter += 1;\n\n                || {}\n            });\n        }\n\n        let resleep = use_sleep()?;\n\n        let value = use_state(|| 0);\n\n        let on_increment = {\n            let value = value.clone();\n\n            Callback::from(move |_: MouseEvent| {\n                value.set(*value + 1);\n            })\n        };\n\n        let on_take_a_break = Callback::from(move |_: MouseEvent| (resleep.clone())());\n\n        Ok(html! {\n            <div class=\"content-area\">\n                <div class=\"actual-result\">{*value}</div>\n                <button class=\"increase\" onclick={on_increment}>{\"increase\"}</button>\n                <div class=\"action-area\">\n                    <button class=\"take-a-break\" onclick={on_take_a_break}>{\"Take a break!\"}</button>\n                </div>\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app(props: &Props) -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content counter={props.counter.clone()} />\n                </Suspense>\n            </div>\n        }\n    }\n\n    let counter = Rc::new(RefCell::new(0_u64));\n\n    let props = Props {\n        counter: counter.clone(),\n    };\n\n    yew::Renderer::<App>::with_root_and_props(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n        props,\n    )\n    .render();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n    assert_eq!(*counter.borrow(), 0); // effects not called.\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">0</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n    assert_eq!(*counter.borrow(), 1); // effects ran 1 time.\n\n    sleep(Duration::from_millis(10)).await;\n\n    gloo::utils::document()\n        .query_selector(\".increase\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    scheduler::flush().await;\n\n    gloo::utils::document()\n        .query_selector(\".increase\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">2</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n    assert_eq!(*counter.borrow(), 3); // effects ran 3 times.\n\n    gloo::utils::document()\n        .query_selector(\".take-a-break\")\n        .unwrap()\n        .unwrap()\n        .dyn_into::<HtmlElement>()\n        .unwrap()\n        .click();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n    assert_eq!(*counter.borrow(), 3); // effects ran 3 times.\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        r#\"<div class=\"content-area\"><div class=\"actual-result\">2</div><button class=\"increase\">increase</button><div class=\"action-area\"><button class=\"take-a-break\">Take a break!</button></div></div>\"#\n    );\n    assert_eq!(*counter.borrow(), 4); // effects ran 4 times.\n}\n\n#[wasm_bindgen_test]\nasync fn use_suspending_future_works() {\n    #[component(Content)]\n    fn content() -> HtmlResult {\n        let _sleep_handle = use_future(|| async move {\n            sleep(Duration::from_millis(50)).await;\n        })?;\n\n        Ok(html! {\n            <div>\n                {\"Content\"}\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content />\n                </Suspense>\n            </div>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), r#\"<div>Content</div>\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn use_suspending_future_with_deps_works() {\n    #[derive(PartialEq, Properties)]\n    struct ContentProps {\n        delay_millis: u64,\n    }\n\n    #[component(Content)]\n    fn content(ContentProps { delay_millis }: &ContentProps) -> HtmlResult {\n        let delayed_result = use_future_with(*delay_millis, |delay_millis| async move {\n            sleep(Duration::from_millis(*delay_millis)).await;\n            42\n        })?;\n\n        Ok(html! {\n            <div>\n                {*delayed_result}\n            </div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n\n        html! {\n            <div id=\"result\">\n                <Suspense {fallback}>\n                    <Content delay_millis={50} />\n                </Suspense>\n            </div>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(10)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), r#\"<div>42</div>\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn test_suspend_forever() {\n    /// A component that its suspension never resumes.\n    /// We test that this can be used with to trigger a suspension and unsuspend upon unmount.\n    #[component]\n    fn SuspendForever() -> HtmlResult {\n        let (s, handle) = Suspension::new();\n        use_state(move || handle);\n        Err(s.into())\n    }\n\n    #[component]\n    fn App() -> Html {\n        let page = use_state(|| 1);\n\n        {\n            let page_setter = page.setter();\n            use_effect_with((), move |_| {\n                spawn_local(async move {\n                    sleep(Duration::from_secs(1)).await;\n                    page_setter.set(2);\n                });\n            });\n        }\n\n        let content = if *page == 1 {\n            html! { <SuspendForever /> }\n        } else {\n            html! { <div id=\"result\">{\"OK\"}</div> }\n        };\n\n        html! {\n            <Suspense fallback={html! {<div>{\"Loading...\"}</div>}}>\n                {content}\n            </Suspense>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(1500)).await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), r#\"OK\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn resume_after_unmount() {\n    #[derive(Clone, Properties, PartialEq)]\n    struct ContentProps {\n        state: UseStateHandle<bool>,\n    }\n\n    #[component(Content)]\n    fn content(ContentProps { state }: &ContentProps) -> HtmlResult {\n        let state = state.clone();\n        let _sleep_handle = use_future(|| async move {\n            sleep(Duration::from_millis(50)).await;\n            state.set(false);\n            sleep(Duration::from_millis(50)).await;\n        })?;\n\n        Ok(html! {\n            <div>{\"Content\"}</div>\n        })\n    }\n\n    #[component(App)]\n    fn app() -> Html {\n        let fallback = html! {<div>{\"wait...\"}</div>};\n        let state = use_state(|| true);\n\n        html! {\n            <div id=\"result\">\n            if *state {\n                <Suspense {fallback}>\n                    <Content {state} />\n                </Suspense>\n            } else {\n                <div>{\"Content replacement\"}</div>\n            }\n            </div>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::from_millis(25)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>wait...</div>\");\n\n    sleep(Duration::from_millis(50)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"<div>Content replacement</div>\");\n}\n\n#[wasm_bindgen_test]\nasync fn test_duplicate_suspension() {\n    use yew::html::ChildrenProps;\n\n    #[component]\n    fn FetchingProvider(props: &ChildrenProps) -> HtmlResult {\n        use_future(|| async {\n            scheduler::flush().await;\n        })?;\n        Ok(html! { <>{props.children.clone()}</> })\n    }\n\n    #[component]\n    fn Child() -> Html {\n        html! {<div id=\"result\">{\"hello!\"}</div>}\n    }\n\n    #[component]\n    fn App() -> Html {\n        let fallback = Html::default();\n        html! {\n           <Suspense {fallback}>\n                <FetchingProvider>\n                    <Child />\n                </FetchingProvider>\n           </Suspense>\n        }\n    }\n\n    yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n    sleep(Duration::from_millis(50)).await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"hello!\");\n}\n"
  },
  {
    "path": "packages/yew/tests/use_callback.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nuse std::sync::atomic::{AtomicBool, Ordering};\n\nmod common;\n\nuse common::obtain_result;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_callback_works() {\n    #[derive(Properties, PartialEq)]\n    struct Props {\n        callback: Callback<String, String>,\n    }\n\n    #[component(MyComponent)]\n    fn my_component(props: &Props) -> Html {\n        let greeting = props.callback.emit(\"Yew\".to_string());\n\n        static CTR: AtomicBool = AtomicBool::new(false);\n\n        if CTR.swap(true, Ordering::Relaxed) {\n            panic!(\"multiple times rendered!\");\n        }\n\n        html! {\n            <div>\n                {\"The test output is: \"}\n                <div id=\"result\">{&greeting}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    #[component(UseCallbackComponent)]\n    fn use_callback_comp() -> Html {\n        let state = use_state(|| 0);\n\n        let callback = use_callback((), move |name, _| format!(\"Hello, {}!\", name));\n\n        use_effect(move || {\n            if *state < 5 {\n                state.set(*state + 1);\n            }\n\n            || {}\n        });\n\n        html! {\n            <div>\n                <MyComponent {callback} />\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseCallbackComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"Hello, Yew!\");\n}\n"
  },
  {
    "path": "packages/yew/tests/use_context.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nuse std::rc::Rc;\n\nuse common::obtain_result_by_id;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_context_scoping_works() {\n    #[derive(Clone, Debug, PartialEq)]\n    struct ExampleContext(String);\n\n    #[component]\n    fn ExpectNoContextComponent() -> Html {\n        let example_context = use_context::<ExampleContext>();\n\n        if example_context.is_some() {\n            console_log!(\n                \"Context should be None here, but was {:?}!\",\n                example_context\n            );\n        };\n        html! {\n            <div></div>\n        }\n    }\n\n    #[component]\n    fn UseContextComponent() -> Html {\n        type ExampleContextProvider = ContextProvider<ExampleContext>;\n        html! {\n            <div>\n                <ExampleContextProvider context={ExampleContext(\"wrong1\".into())}>\n                    <div>{\"ignored\"}</div>\n                </ExampleContextProvider>\n                <ExampleContextProvider context={ExampleContext(\"wrong2\".into())}>\n                    <ExampleContextProvider context={ExampleContext(\"correct\".into())}>\n                        <ExampleContextProvider context={ExampleContext(\"wrong1\".into())}>\n                            <div>{\"ignored\"}</div>\n                        </ExampleContextProvider>\n                        <UseContextComponentInner />\n                    </ExampleContextProvider>\n                </ExampleContextProvider>\n                <ExampleContextProvider context={ExampleContext(\"wrong3\".into())}>\n                    <div>{\"ignored\"}</div>\n                </ExampleContextProvider>\n                <ExpectNoContextComponent />\n            </div>\n        }\n    }\n\n    #[component]\n    fn UseContextComponentInner() -> Html {\n        let context = use_context::<ExampleContext>();\n        html! {\n            <div id=\"result\">{ &context.unwrap().0 }</div>\n        }\n    }\n\n    yew::Renderer::<UseContextComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n\n    let result: String = obtain_result_by_id(\"result\");\n    assert_eq!(\"correct\", result);\n}\n\n#[wasm_bindgen_test]\nasync fn use_context_works_with_multiple_types() {\n    #[derive(Clone, Debug, PartialEq)]\n    struct ContextA(u32);\n    #[derive(Clone, Debug, PartialEq)]\n    struct ContextB(u32);\n\n    #[component]\n    fn Test1() -> Html {\n        let ctx_a = use_context::<ContextA>();\n        let ctx_b = use_context::<ContextB>();\n\n        assert_eq!(ctx_a, Some(ContextA(2)));\n        assert_eq!(ctx_b, Some(ContextB(1)));\n\n        html! {}\n    }\n\n    #[component]\n    fn Test2() -> Html {\n        let ctx_a = use_context::<ContextA>();\n        let ctx_b = use_context::<ContextB>();\n\n        assert_eq!(ctx_a, Some(ContextA(0)));\n        assert_eq!(ctx_b, Some(ContextB(1)));\n\n        html! {}\n    }\n\n    #[component]\n    fn Test3() -> Html {\n        let ctx_a = use_context::<ContextA>();\n        let ctx_b = use_context::<ContextB>();\n\n        assert_eq!(ctx_a, Some(ContextA(0)));\n        assert_eq!(ctx_b, None);\n\n        html! {}\n    }\n\n    #[component]\n    fn Test4() -> Html {\n        let ctx_a = use_context::<ContextA>();\n        let ctx_b = use_context::<ContextB>();\n\n        assert_eq!(ctx_a, None);\n        assert_eq!(ctx_b, None);\n\n        html! {}\n    }\n\n    #[component]\n    fn TestComponent() -> Html {\n        type ContextAProvider = ContextProvider<ContextA>;\n        type ContextBProvider = ContextProvider<ContextB>;\n\n        html! {\n            <div>\n                <ContextAProvider context={ContextA(0)}>\n                    <ContextBProvider context={ContextB(1)}>\n                        <ContextAProvider context={ContextA(2)}>\n                            <Test1/>\n                        </ContextAProvider>\n                        <Test2/>\n                    </ContextBProvider>\n                    <Test3/>\n                </ContextAProvider>\n                <Test4 />\n            </div>\n        }\n    }\n\n    yew::Renderer::<TestComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n}\n\n#[wasm_bindgen_test]\nasync fn use_context_update_works() {\n    #[derive(Clone, Debug, PartialEq)]\n    struct MyContext(String);\n\n    #[derive(Clone, Debug, PartialEq, Properties)]\n    struct RenderCounterProps {\n        id: String,\n        children: Children,\n    }\n\n    #[component]\n    fn RenderCounter(props: &RenderCounterProps) -> Html {\n        let counter = use_mut_ref(|| 0);\n        *counter.borrow_mut() += 1;\n        html! {\n            <>\n                <div id={props.id.clone()}>\n                    { format!(\"total: {}\", counter.borrow()) }\n                </div>\n                { props.children.clone() }\n            </>\n        }\n    }\n\n    #[derive(Clone, Debug, PartialEq, Properties)]\n    struct ContextOutletProps {\n        id: String,\n        #[prop_or_default]\n        magic: usize,\n    }\n\n    #[component]\n    fn ContextOutlet(props: &ContextOutletProps) -> Html {\n        let counter = use_mut_ref(|| 0);\n        *counter.borrow_mut() += 1;\n\n        let ctx = use_context::<Rc<MyContext>>().expect(\"context not passed down\");\n\n        html! {\n            <>\n                <div>{ format!(\"magic: {}\\n\", props.magic) }</div>\n                <div id={props.id.clone()}>\n                    { format!(\"current: {}, total: {}\", ctx.0, counter.borrow()) }\n                </div>\n            </>\n        }\n    }\n\n    #[component]\n    fn TestComponent() -> Html {\n        type MyContextProvider = ContextProvider<Rc<MyContext>>;\n\n        let ctx = use_state(|| MyContext(\"hello\".into()));\n        let rendered = use_mut_ref(|| 0);\n\n        // this is used to force an update specific to test-2\n        let magic_rc = use_state(|| 0);\n        let magic: usize = *magic_rc;\n        {\n            let ctx = ctx.clone();\n            use_effect(move || {\n                let count = *rendered.borrow();\n                match count {\n                    0 => {\n                        ctx.set(MyContext(\"world\".into()));\n                        *rendered.borrow_mut() += 1;\n                    }\n                    1 => {\n                        // force test-2 to re-render.\n                        magic_rc.set(1);\n                        *rendered.borrow_mut() += 1;\n                    }\n                    2 => {\n                        ctx.set(MyContext(\"hello world!\".into()));\n                        *rendered.borrow_mut() += 1;\n                    }\n                    _ => (),\n                };\n                || {}\n            });\n        }\n        html! {\n            <MyContextProvider context={Rc::new((*ctx).clone())}>\n                <RenderCounter id=\"test-0\">\n                    <ContextOutlet id=\"test-1\" />\n                    <ContextOutlet id=\"test-2\" {magic} />\n                </RenderCounter>\n            </MyContextProvider>\n        }\n    }\n\n    yew::Renderer::<TestComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n\n    // 1 initial render + 1 magic\n    assert_eq!(obtain_result_by_id(\"test-0\"), \"total: 2\");\n\n    // 1 initial + 2 context update\n    assert_eq!(\n        obtain_result_by_id(\"test-1\"),\n        \"current: hello world!, total: 3\"\n    );\n\n    // 1 initial + 1 context update + 1 magic update + 1 context update\n    assert_eq!(\n        obtain_result_by_id(\"test-2\"),\n        \"current: hello world!, total: 4\"\n    );\n}\n"
  },
  {
    "path": "packages/yew/tests/use_effect.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nuse std::ops::{Deref, DerefMut};\nuse std::rc::Rc;\n\nuse common::obtain_result;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_effect_destroys_on_component_drop() {\n    #[derive(Properties, Clone)]\n    struct WrapperProps {\n        destroy_called: Rc<dyn Fn()>,\n    }\n    impl PartialEq for WrapperProps {\n        fn eq(&self, _other: &Self) -> bool {\n            false\n        }\n    }\n    #[derive(Properties, Clone)]\n    struct FunctionProps {\n        effect_called: Rc<dyn Fn()>,\n        destroy_called: Rc<dyn Fn()>,\n    }\n    impl PartialEq for FunctionProps {\n        fn eq(&self, _other: &Self) -> bool {\n            false\n        }\n    }\n\n    #[component(UseEffectComponent)]\n    fn use_effect_comp(props: &FunctionProps) -> Html {\n        let effect_called = props.effect_called.clone();\n        let destroy_called = props.destroy_called.clone();\n        use_effect_with((), move |_| {\n            effect_called();\n            #[allow(clippy::redundant_closure)] // Otherwise there is a build error\n            move || destroy_called()\n        });\n        html! {}\n    }\n\n    #[component(UseEffectWrapperComponent)]\n    fn use_effect_wrapper_comp(props: &WrapperProps) -> Html {\n        let show = use_state(|| true);\n        if *show {\n            let effect_called: Rc<dyn Fn()> = { Rc::new(move || show.set(false)) };\n            html! {\n                <UseEffectComponent destroy_called={props.destroy_called.clone()} {effect_called} />\n            }\n        } else {\n            html! {\n                <div>{ \"EMPTY\" }</div>\n            }\n        }\n    }\n\n    let destroy_counter = Rc::new(std::cell::RefCell::new(0));\n    let destroy_counter_c = destroy_counter.clone();\n    yew::Renderer::<UseEffectWrapperComponent>::with_root_and_props(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n        WrapperProps {\n            destroy_called: Rc::new(move || *destroy_counter_c.borrow_mut().deref_mut() += 1),\n        },\n    )\n    .render();\n\n    scheduler::flush().await;\n\n    assert_eq!(1, *destroy_counter.borrow().deref());\n}\n\n#[wasm_bindgen_test]\nasync fn use_effect_works_many_times() {\n    #[component(UseEffectComponent)]\n    fn use_effect_comp() -> Html {\n        let counter = use_state(|| 0);\n        let counter_clone = counter.clone();\n\n        use_effect_with(*counter, move |_| {\n            if *counter_clone < 4 {\n                counter_clone.set(*counter_clone + 1);\n            }\n            || {}\n        });\n\n        html! {\n            <div>\n                { \"The test result is\" }\n                <div id=\"result\">{ *counter }</div>\n                { \"\\n\" }\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseEffectComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"4\");\n}\n\n#[wasm_bindgen_test]\nasync fn use_effect_works_once() {\n    #[component(UseEffectComponent)]\n    fn use_effect_comp() -> Html {\n        let counter = use_state(|| 0);\n        let counter_clone = counter.clone();\n\n        use_effect_with((), move |_| {\n            counter_clone.set(*counter_clone + 1);\n            || panic!(\"Destructor should not have been called\")\n        });\n\n        html! {\n            <div>\n                { \"The test result is\" }\n                <div id=\"result\">{ *counter }</div>\n                { \"\\n\" }\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseEffectComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n\n    assert_eq!(result.as_str(), \"1\");\n}\n\n#[wasm_bindgen_test]\nasync fn use_effect_refires_on_dependency_change() {\n    #[component(UseEffectComponent)]\n    fn use_effect_comp() -> Html {\n        let number_ref = use_mut_ref(|| 0);\n        let number_ref_c = number_ref.clone();\n        let number_ref2 = use_mut_ref(|| 0);\n        let number_ref2_c = number_ref2.clone();\n        let arg = *number_ref.borrow_mut().deref_mut();\n        let counter = use_state(|| 0);\n        use_effect_with(arg, move |dep| {\n            let mut ref_mut = number_ref_c.borrow_mut();\n            let inner_ref_mut = ref_mut.deref_mut();\n            if *inner_ref_mut < 1 {\n                *inner_ref_mut += 1;\n                assert_eq!(dep, &0);\n            } else {\n                assert_eq!(dep, &1);\n            }\n            counter.set(10); // we just need to make sure it does not panic\n            move || {\n                counter.set(11);\n                *number_ref2_c.borrow_mut().deref_mut() += 1;\n            }\n        });\n        html! {\n            <div>\n                {\"The test result is\"}\n                <div id=\"result\">{*number_ref.borrow_mut().deref_mut()}{*number_ref2.borrow_mut().deref_mut()}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseEffectComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n    let result: String = obtain_result();\n\n    assert_eq!(result.as_str(), \"11\");\n}\n"
  },
  {
    "path": "packages/yew/tests/use_memo.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nuse std::sync::atomic::{AtomicBool, Ordering};\n\nmod common;\n\nuse common::obtain_result;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_memo_works() {\n    #[component(UseMemoComponent)]\n    fn use_memo_comp() -> Html {\n        let state = use_state(|| 0);\n\n        let memoed_val = use_memo((), |_| {\n            static CTR: AtomicBool = AtomicBool::new(false);\n\n            if CTR.swap(true, Ordering::Relaxed) {\n                panic!(\"multiple times rendered!\");\n            }\n\n            \"true\"\n        });\n\n        use_effect(move || {\n            if *state < 5 {\n                state.set(*state + 1);\n            }\n\n            || {}\n        });\n\n        html! {\n            <div>\n                {\"The test output is: \"}\n                <div id=\"result\">{*memoed_val}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseMemoComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"true\");\n}\n"
  },
  {
    "path": "packages/yew/tests/use_prepared_state.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n#![cfg(feature = \"hydration\")]\n#![cfg_attr(nightly_yew, feature(async_closure))]\n\nuse std::time::Duration;\n\nmod common;\n\nuse common::obtain_result_by_id;\nuse wasm_bindgen_test::*;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew::{scheduler, Renderer, ServerRenderer};\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_prepared_state_works() {\n    #[component]\n    fn Comp() -> HtmlResult {\n        let ctr = use_prepared_state!((), |_| -> u32 { 12345 })?.unwrap_or_default();\n\n        Ok(html! {\n            <div>\n                {*ctr}\n            </div>\n        })\n    }\n\n    #[component]\n    fn App() -> Html {\n        html! {\n            <Suspense fallback={Html::default()}>\n                <div>\n                    <Comp />\n                </div>\n            </Suspense>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    assert_eq!(\n        s,\n        r#\"<!--<[use_prepared_state::use_prepared_state_works::{{closure}}::App]>--><!--<[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--<[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--<?>--><div><!--<[use_prepared_state::use_prepared_state_works::{{closure}}::Comp]>--><div>12345</div><script type=\"application/x-yew-comp-state\">Afs5MAE=</script><!--</[use_prepared_state::use_prepared_state_works::{{closure}}::Comp]>--></div><!--</?>--><!--</[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--</[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--</[use_prepared_state::use_prepared_state_works::{{closure}}::App]>-->\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    sleep(Duration::from_millis(200)).await;\n\n    let result = obtain_result_by_id(\"output\");\n\n    // no placeholders, hydration is successful and state 12345 is preserved.\n    assert_eq!(result, r#\"<div><div>12345</div></div>\"#);\n}\n\n#[wasm_bindgen_test]\nasync fn use_prepared_state_with_suspension_works() {\n    #[component]\n    fn Comp() -> HtmlResult {\n        let ctr = use_prepared_state!((), async move |_| -> u32 { 12345 })?.unwrap_or_default();\n\n        Ok(html! {\n            <div>\n                {*ctr}\n            </div>\n        })\n    }\n\n    #[component]\n    fn App() -> Html {\n        html! {\n            <Suspense fallback={Html::default()}>\n                <div>\n                    <Comp />\n                </div>\n            </Suspense>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    assert_eq!(\n        s,\n        r#\"<!--<[use_prepared_state::use_prepared_state_with_suspension_works::{{closure}}::App]>--><!--<[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--<[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--<?>--><div><!--<[use_prepared_state::use_prepared_state_with_suspension_works::{{closure}}::Comp]>--><div>12345</div><script type=\"application/x-yew-comp-state\">Afs5MAE=</script><!--</[use_prepared_state::use_prepared_state_with_suspension_works::{{closure}}::Comp]>--></div><!--</?>--><!--</[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--</[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--</[use_prepared_state::use_prepared_state_with_suspension_works::{{closure}}::App]>-->\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    sleep(Duration::from_millis(200)).await;\n\n    let result = obtain_result_by_id(\"output\");\n\n    // no placeholders, hydration is successful and state 12345 is preserved.\n    assert_eq!(result, r#\"<div><div>12345</div></div>\"#);\n}\n"
  },
  {
    "path": "packages/yew/tests/use_reducer.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nuse std::collections::HashSet;\nuse std::rc::Rc;\n\nuse gloo::utils::document;\nuse wasm_bindgen::JsCast;\nuse wasm_bindgen_test::*;\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nmod common;\n\nuse common::obtain_result;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[derive(Debug)]\nstruct CounterState {\n    counter: i32,\n}\n\nimpl Reducible for CounterState {\n    type Action = i32;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        Self {\n            counter: self.counter + action,\n        }\n        .into()\n    }\n}\n\n#[wasm_bindgen_test]\nasync fn use_reducer_works() {\n    #[component(UseReducerComponent)]\n    fn use_reducer_comp() -> Html {\n        let counter = use_reducer(|| CounterState { counter: 10 });\n\n        let counter_clone = counter.clone();\n        use_effect_with((), move |_| {\n            counter_clone.dispatch(1);\n            || {}\n        });\n        html! {\n            <div>\n                {\"The test result is\"}\n                <div id=\"result\">{counter.counter}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseReducerComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n    let result = obtain_result();\n\n    assert_eq!(result.as_str(), \"11\");\n}\n\n#[derive(Debug, Clone, PartialEq)]\nstruct ContentState {\n    content: HashSet<String>,\n}\n\nimpl Reducible for ContentState {\n    type Action = String;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        let mut self_: Self = (*self).clone();\n        self_.content.insert(action);\n        self_.into()\n    }\n}\n\n#[wasm_bindgen_test]\nasync fn use_reducer_eq_works() {\n    #[component(UseReducerComponent)]\n    fn use_reducer_comp() -> Html {\n        let content = use_reducer_eq(|| ContentState {\n            content: HashSet::default(),\n        });\n\n        let render_count = use_mut_ref(|| 0);\n\n        let render_count = {\n            let mut render_count = render_count.borrow_mut();\n            *render_count += 1;\n\n            *render_count\n        };\n\n        let add_content_a = {\n            let content = content.clone();\n            Callback::from(move |_| content.dispatch(\"A\".to_string()))\n        };\n\n        let add_content_b = Callback::from(move |_| content.dispatch(\"B\".to_string()));\n\n        html! {\n            <>\n                <div>\n                    {\"This component has been rendered: \"}<span id=\"result\">{render_count}</span>{\" Time(s).\"}\n                </div>\n                <button onclick={add_content_a} id=\"add-a\">{\"Add A to Content\"}</button>\n                <button onclick={add_content_b} id=\"add-b\">{\"Add B to Content\"}</button>\n            </>\n        }\n    }\n\n    yew::Renderer::<UseReducerComponent>::with_root(\n        document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"1\");\n\n    document()\n        .get_element_by_id(\"add-a\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"2\");\n\n    document()\n        .get_element_by_id(\"add-a\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"2\");\n\n    document()\n        .get_element_by_id(\"add-b\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"3\");\n\n    document()\n        .get_element_by_id(\"add-b\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"3\");\n}\n\nenum SometimesChangeAction {\n    /// If this action is sent, the state will remain the same\n    Keep,\n    /// If this action is sent, the state will change\n    Change,\n}\n\n/// A state that does not implement PartialEq\n#[derive(Clone)]\nstruct SometimesChangingState {\n    value: i32,\n}\n\nimpl Reducible for SometimesChangingState {\n    type Action = SometimesChangeAction;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        use SometimesChangeAction::*;\n        match action {\n            Keep => self,\n            Change => {\n                let mut self_: Self = (*self).clone();\n                self_.value += 1;\n                self_.into()\n            }\n        }\n    }\n}\n\n#[wasm_bindgen_test]\nasync fn use_reducer_does_not_rerender_when_rc_is_reused() {\n    #[component(UseReducerComponent)]\n    fn use_reducer_comp() -> Html {\n        let state = use_reducer(|| SometimesChangingState { value: 0 });\n        let render_count = use_mut_ref(|| 0);\n\n        let render_count = {\n            let mut render_count = render_count.borrow_mut();\n            *render_count += 1;\n\n            *render_count\n        };\n\n        let keep_state = {\n            let state = state.clone();\n            Callback::from(move |_| state.dispatch(SometimesChangeAction::Keep))\n        };\n\n        let change_state = Callback::from(move |_| state.dispatch(SometimesChangeAction::Change));\n\n        html! {\n            <>\n                <div>\n                    {\"This component has been rendered: \"}<span id=\"result\">{render_count}</span>{\" Time(s).\"}\n                </div>\n                <button onclick={keep_state} id=\"keep-state\">{\"Keep State\"}</button>\n                <button onclick={change_state} id=\"change-state\">{\"Change State\"}</button>\n            </>\n        }\n    }\n\n    yew::Renderer::<UseReducerComponent>::with_root(\n        document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"1\");\n\n    document()\n        .get_element_by_id(\"change-state\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"2\");\n\n    document()\n        .get_element_by_id(\"keep-state\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"2\");\n}\n"
  },
  {
    "path": "packages/yew/tests/use_ref.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nuse std::ops::DerefMut;\n\nuse common::obtain_result;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_ref_works() {\n    #[component(UseRefComponent)]\n    fn use_ref_comp() -> Html {\n        let ref_example = use_mut_ref(|| 0);\n        *ref_example.borrow_mut().deref_mut() += 1;\n        let counter = use_state(|| 0);\n        if *counter < 5 {\n            counter.set(*counter + 1)\n        }\n        html! {\n            <div>\n                {\"The test output is: \"}\n                <div id=\"result\">{*ref_example.borrow_mut().deref_mut() > 4}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseRefComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"true\");\n}\n"
  },
  {
    "path": "packages/yew/tests/use_state.rs",
    "content": "#![cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\n\nmod common;\n\nuse common::obtain_result;\nuse wasm_bindgen_test::*;\nuse yew::prelude::*;\nuse yew::scheduler;\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_state_works() {\n    #[component(UseComponent)]\n    fn use_state_comp() -> Html {\n        let counter = use_state(|| 0);\n        if *counter < 5 {\n            counter.set(*counter + 1)\n        }\n        html! {\n            <div>\n                {\"Test Output: \"}\n                <div id=\"result\">{*counter}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"5\");\n}\n\n#[wasm_bindgen_test]\nasync fn multiple_use_state_setters() {\n    #[component(UseComponent)]\n    fn use_state_comp() -> Html {\n        let counter = use_state(|| 0);\n        let counter_clone = counter.clone();\n        use_effect_with((), move |_| {\n            // 1st location\n            counter_clone.set(*counter_clone + 1);\n            || {}\n        });\n        let another_scope = {\n            let counter = counter.clone();\n            move || {\n                if *counter < 11 {\n                    // 2nd location\n                    counter.set(*counter + 10)\n                }\n            }\n        };\n        another_scope();\n        html! {\n            <div>\n                { \"Test Output: \" }\n                // expected output\n                <div id=\"result\">{ *counter }</div>\n                { \"\\n\" }\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"11\");\n}\n\n#[wasm_bindgen_test]\nasync fn use_state_eq_works() {\n    use std::sync::atomic::{AtomicUsize, Ordering};\n    static RENDER_COUNT: AtomicUsize = AtomicUsize::new(0);\n\n    #[component(UseComponent)]\n    fn use_state_comp() -> Html {\n        RENDER_COUNT.fetch_add(1, Ordering::Relaxed);\n        let counter = use_state_eq(|| 0);\n        counter.set(1);\n\n        html! {\n            <div>\n                {\"Test Output: \"}\n                <div id=\"result\">{*counter}</div>\n                {\"\\n\"}\n            </div>\n        }\n    }\n\n    yew::Renderer::<UseComponent>::with_root(\n        gloo::utils::document().get_element_by_id(\"output\").unwrap(),\n    )\n    .render();\n    scheduler::flush().await;\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"1\");\n    assert_eq!(RENDER_COUNT.load(Ordering::Relaxed), 2);\n}\n\n/// Exercises the exact pattern that causes use-after-free in the original PR #3963\n/// fix, where `UseReducerHandle::deref()` drops the `Ref` guard but returns a\n/// pointer derived from it.\n///\n/// The dangerous sequence within a single callback:\n///   1. `handle.set(v1)` — dispatch puts a *new* `Rc` (refcount=1) in the shared `RefCell`,\n///      replacing the one from render time.\n///   2. `let r: &T = &*handle` — `deref()` borrows the RefCell, grabs a raw pointer into the Rc\n///      (refcount still 1), and **drops the `Ref` guard**.\n///   3. `handle.set(v2)` — dispatch replaces that Rc. Because its refcount was 1, it is freed. `r`\n///      is now dangling.\n///   4. Allocate objects of similar size to encourage the allocator to reuse the freed memory,\n///      overwriting the old `T`.\n///   5. Read through `r` — **use-after-free**.\n///\n/// With the `deref_history` fix, step 2 clones the Rc into a `Vec` kept alive by\n/// the handle, bumping the refcount to 2. Step 3 only drops it to 1, so the\n/// allocation survives and `r` remains valid.\n#[wasm_bindgen_test]\nasync fn deref_remains_valid_across_multiple_dispatches_in_callback() {\n    use std::cell::RefCell;\n\n    use gloo::utils::document;\n    use wasm_bindgen::JsCast;\n    use web_sys::HtmlElement;\n\n    thread_local! {\n        static DEREF_RESULT: RefCell<Option<String>> = const { RefCell::new(None) };\n    }\n\n    #[component(UBTestComponent)]\n    fn ub_test_comp() -> Html {\n        let state = use_state(|| \"initial\".to_string());\n\n        let trigger = {\n            let state = state.clone();\n            Callback::from(move |_| {\n                // Step 1: dispatch. The RefCell now contains a *new* Rc whose only\n                // owner is the RefCell itself (refcount = 1).\n                state.set(\"first_dispatch\".to_string());\n\n                // Step 2: deref. In the original fix the Ref guard is dropped\n                // immediately, leaving us with a bare pointer into the refcount-1\n                // Rc. With deref_history, the Rc is cloned into the Vec so the\n                // refcount is bumped to 2.\n                let borrowed: &String = &*state;\n\n                // Step 3: dispatch again. The RefCell's old Rc is replaced.\n                // Original fix: refcount was 1 → drops to 0 → freed → `borrowed`\n                //   dangles.\n                // deref_history fix: refcount was 2 → drops to 1 (still in Vec)\n                //   → allocation survives → `borrowed` is valid.\n                state.set(\"second_dispatch\".to_string());\n\n                // Step 4: churn the allocator. Create and drop many heap objects\n                // of ~32 bytes (the size of the freed Rc+UseStateReducer+String\n                // struct on wasm32) to maximize the chance that the allocator\n                // hands out the freed address to one of these, overwriting the\n                // memory `borrowed` points into.\n                for _ in 0..256 {\n                    // Each Box<[u8; 32]> is roughly the same size as the freed Rc\n                    // allocation containing UseStateReducer<String>.\n                    let overwrite = Box::new([0xFFu8; 32]);\n                    std::hint::black_box(&*overwrite);\n                    drop(overwrite);\n                }\n\n                // Also allocate Strings whose *buffers* might reuse the freed\n                // String buffer from step 1.\n                let _noise: Vec<String> = (0..64).map(|i| format!(\"noise_{:032}\", i)).collect();\n\n                // Step 5: read through the potentially-dangling reference.\n                // With the original fix this is UB: the memory behind `borrowed`\n                // may have been reused by the allocations above, so `.clone()`\n                // could read a garbage ptr/len/cap triple and trap, or silently\n                // return corrupted data.\n                // With deref_history, this always reads \"first_dispatch\".\n                let value = borrowed.clone();\n\n                DEREF_RESULT.with(|r| {\n                    *r.borrow_mut() = Some(value);\n                });\n            })\n        };\n\n        html! {\n            <div>\n                <button id=\"ub-trigger\" onclick={trigger}>{\"Trigger\"}</button>\n                <div id=\"result\">{(*state).clone()}</div>\n            </div>\n        }\n    }\n\n    yew::Renderer::<UBTestComponent>::with_root(document().get_element_by_id(\"output\").unwrap())\n        .render();\n    scheduler::flush().await;\n\n    // Fire the callback\n    document()\n        .get_element_by_id(\"ub-trigger\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n\n    scheduler::flush().await;\n\n    // The reference obtained between the two dispatches must still read the\n    // value from the first dispatch, not garbage or \"second_dispatch\".\n    let captured = DEREF_RESULT.with(|r| r.borrow().clone());\n    assert_eq!(\n        captured,\n        Some(\"first_dispatch\".to_string()),\n        \"deref() reference must remain valid across subsequent dispatches\"\n    );\n}\n\n/// Regression test for issue #3796\n/// Tests that state handles always read the latest value even when accessed\n/// from callbacks before a rerender occurs.\n///\n/// The bug occurred when:\n/// 1. State A is updated via set()\n/// 2. State B is updated via set()\n/// 3. A callback reads both states before rerender\n/// 4. The callback would see stale value for B because the handle was caching a snapshot instead of\n///    reading from the shared RefCell\n#[wasm_bindgen_test]\nasync fn use_state_handles_read_latest_value_issue_3796() {\n    use std::cell::RefCell;\n\n    use gloo::utils::document;\n    use wasm_bindgen::JsCast;\n    use web_sys::HtmlElement;\n\n    // Shared storage for the values read by the submit handler\n    thread_local! {\n        static CAPTURED_VALUES: RefCell<Option<(String, String)>> = const { RefCell::new(None) };\n    }\n\n    #[component(FormComponent)]\n    fn form_comp() -> Html {\n        let field_a = use_state(String::new);\n        let field_b = use_state(String::new);\n\n        let update_a = {\n            let field_a = field_a.clone();\n            Callback::from(move |_| {\n                field_a.set(\"value_a\".to_string());\n            })\n        };\n\n        let update_b = {\n            let field_b = field_b.clone();\n            Callback::from(move |_| {\n                field_b.set(\"value_b\".to_string());\n            })\n        };\n\n        // This callback reads both states - the bug caused field_b to be stale\n        let submit = {\n            let field_a = field_a.clone();\n            let field_b = field_b.clone();\n            Callback::from(move |_| {\n                let a = (*field_a).clone();\n                let b = (*field_b).clone();\n                CAPTURED_VALUES.with(|v| {\n                    *v.borrow_mut() = Some((a.clone(), b.clone()));\n                });\n            })\n        };\n\n        html! {\n            <div>\n                <button id=\"update-a\" onclick={update_a}>{\"Update A\"}</button>\n                <button id=\"update-b\" onclick={update_b}>{\"Update B\"}</button>\n                <button id=\"submit\" onclick={submit}>{\"Submit\"}</button>\n                <div id=\"result\">{format!(\"a={}, b={}\", *field_a, *field_b)}</div>\n            </div>\n        }\n    }\n\n    yew::Renderer::<FormComponent>::with_root(document().get_element_by_id(\"output\").unwrap())\n        .render();\n    scheduler::flush().await;\n\n    // Initial state\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"a=, b=\");\n\n    // Click update-a, then update-b, then submit WITHOUT waiting for rerender.\n    // This simulates rapid user interaction (like the Firefox bug in issue #3796).\n    document()\n        .get_element_by_id(\"update-a\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n\n    document()\n        .get_element_by_id(\"update-b\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n\n    document()\n        .get_element_by_id(\"submit\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n\n    // Now wait for rerenders to complete\n    scheduler::flush().await;\n\n    // Check the values captured by the submit handler.\n    // Before the fix, field_b would be empty because the callback captured a stale handle.\n    let captured = CAPTURED_VALUES.with(|v| v.borrow().clone());\n    assert_eq!(\n        captured,\n        Some((\"value_a\".to_string(), \"value_b\".to_string())),\n        \"Submit handler should see latest values for both fields\"\n    );\n\n    // Also verify the DOM shows correct values after rerender\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"a=value_a, b=value_b\");\n}\n\n/// Regression test for issue #4058\n///\n/// When a UseStateHandle is passed as a prop to a child component, updating the\n/// state should cause the child to re-render. After the deref_history change\n/// (PR #3988), UseReducerHandle::eq dereferences both old and new handles, but\n/// since Deref now always reads from the shared RefCell, both sides resolve to\n/// the latest value, making eq always return true and preventing child re-renders.\n#[wasm_bindgen_test]\nasync fn use_state_handle_as_prop_triggers_child_rerender_issue_4058() {\n    use std::sync::atomic::{AtomicUsize, Ordering};\n\n    use gloo::utils::document;\n    use wasm_bindgen::JsCast;\n    use web_sys::HtmlElement;\n\n    static CHILD_RENDER_COUNT: AtomicUsize = AtomicUsize::new(0);\n\n    #[derive(Properties, PartialEq)]\n    struct ChildProps {\n        handle: UseStateHandle<i32>,\n    }\n\n    #[component(ChildComponent)]\n    fn child_comp(props: &ChildProps) -> Html {\n        CHILD_RENDER_COUNT.fetch_add(1, Ordering::Relaxed);\n\n        let onclick = {\n            let handle = props.handle.clone();\n            Callback::from(move |_| {\n                handle.set(*handle + 1);\n            })\n        };\n\n        html! {\n            <div>\n                <button id=\"child-increment\" {onclick}>{\"Increment\"}</button>\n                <div id=\"result\">{ *props.handle }</div>\n            </div>\n        }\n    }\n\n    #[component(ParentComponent)]\n    fn parent_comp() -> Html {\n        let state = use_state(|| 0);\n        html! {\n            <ChildComponent handle={state} />\n        }\n    }\n\n    CHILD_RENDER_COUNT.store(0, Ordering::Relaxed);\n\n    yew::Renderer::<ParentComponent>::with_root(document().get_element_by_id(\"output\").unwrap())\n        .render();\n    scheduler::flush().await;\n\n    // Initial render: child should show 0\n    let result = obtain_result();\n    assert_eq!(result.as_str(), \"0\");\n    assert_eq!(CHILD_RENDER_COUNT.load(Ordering::Relaxed), 1);\n\n    // Click the increment button in the child\n    document()\n        .get_element_by_id(\"child-increment\")\n        .unwrap()\n        .unchecked_into::<HtmlElement>()\n        .click();\n\n    scheduler::flush().await;\n\n    // After increment: child should re-render and show 1\n    let result = obtain_result();\n    assert_eq!(\n        result.as_str(),\n        \"1\",\n        \"Child component must re-render when UseStateHandle prop changes (issue #4058)\"\n    );\n    assert!(\n        CHILD_RENDER_COUNT.load(Ordering::Relaxed) >= 2,\n        \"Child must have re-rendered at least twice, but rendered {} times\",\n        CHILD_RENDER_COUNT.load(Ordering::Relaxed)\n    );\n}\n"
  },
  {
    "path": "packages/yew/tests/use_transitive_state.rs",
    "content": "#![cfg(feature = \"hydration\")]\n#![cfg(target_arch = \"wasm32\")]\n\nuse std::time::Duration;\n\nmod common;\n\nuse common::obtain_result_by_id;\nuse wasm_bindgen_test::*;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew::{scheduler, Renderer, ServerRenderer};\n\nwasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n#[wasm_bindgen_test]\nasync fn use_transitive_state_works() {\n    #[component]\n    fn Comp() -> HtmlResult {\n        let ctr = use_transitive_state!((), |_| -> u32 { 12345 })?.unwrap_or_default();\n\n        Ok(html! {\n            <div>\n                {*ctr}\n            </div>\n        })\n    }\n\n    #[component]\n    fn App() -> Html {\n        html! {\n            <Suspense fallback={Html::default()}>\n                <div>\n                    <Comp />\n                </div>\n            </Suspense>\n        }\n    }\n\n    let s = ServerRenderer::<App>::new().render().await;\n\n    assert_eq!(\n        s,\n        // div text content should be 0 but state should be 12345.\n        r#\"<!--<[use_transitive_state::use_transitive_state_works::{{closure}}::App]>--><!--<[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--<[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--<?>--><div><!--<[use_transitive_state::use_transitive_state_works::{{closure}}::Comp]>--><div>0</div><script type=\"application/x-yew-comp-state\">Afs5MAE=</script><!--</[use_transitive_state::use_transitive_state_works::{{closure}}::Comp]>--></div><!--</?>--><!--</[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--</[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--</[use_transitive_state::use_transitive_state_works::{{closure}}::App]>-->\"#\n    );\n\n    gloo::utils::document()\n        .query_selector(\"#output\")\n        .unwrap()\n        .unwrap()\n        .set_inner_html(&s);\n\n    scheduler::flush().await;\n\n    Renderer::<App>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .hydrate();\n\n    sleep(Duration::from_millis(200)).await;\n\n    let result = obtain_result_by_id(\"output\");\n\n    // no placeholders, hydration is successful and div text content now becomes 12345.\n    assert_eq!(result, r#\"<div><div>12345</div></div>\"#);\n}\n"
  },
  {
    "path": "packages/yew-agent/Cargo.toml",
    "content": "[package]\nname = \"yew-agent\"\nversion = \"0.5.0\"\nauthors = [\"Hamza <muhammadhamza1311@gmail.com>\"]\nrepository = \"https://github.com/yewstack/yew\"\nhomepage = \"https://yew.rs\"\ndocumentation = \"https://docs.rs/yew/\"\nedition = \"2021\"\nreadme = \"../../README.md\"\ndescription = \"Agents for Yew\"\nlicense = \"MIT OR Apache-2.0\"\nrust-version = \"1.84.0\"\n\n[dependencies]\nyew = { version = \"0.23.0\", path = \"../yew\" }\nwasm-bindgen.workspace = true\njs-sys.workspace = true\npinned = \"0.1.0\"\nthiserror.workspace = true\nbincode = { workspace = true }\nwasm-bindgen-futures.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nfutures.workspace = true\nyew-agent-macro = { version = \"0.4\", path = \"../yew-agent-macro\" }\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"Blob\",\n    \"BlobPropertyBag\",\n    \"DedicatedWorkerGlobalScope\",\n    \"MessageEvent\",\n    \"Url\",\n    \"Worker\",\n    \"WorkerOptions\",\n\t\"WorkerType\"\n]\n\n[dev-dependencies]\nserde = { workspace = true }\n"
  },
  {
    "path": "packages/yew-agent/README.md",
    "content": "# Yew Agent\n\nThis module contains Yew's web worker implementation.\n\n## Types\n\nThere're a couple kinds of agents:\n\n### Oneshot\n\nA kind of agent that for each input, a single output is returned.\n\n#### Reactor\n\nA kind of agent that can send many inputs and receive many outputs over a single bridge.\n\n#### Worker\n\nThe low-level implementation of agents that provides an actor model and communicates with\nmultiple bridges.\n\n## Reachability\n\nWhen an agent is spawned, each agent is associated with a reachability.\n\n### Private\n\nEach time a bridge is created, a new instance\nof agent is spawned. This allows parallel computing between agents.\n\n#### Public\n\nPublic agents are shared among all children of a provider.\nOnly 1 instance will be spawned for each public agents provider.\n\n### Provider\n\nEach Agent requires a provider to provide communications and maintain bridges.\nAll hooks must be called within a provider.\n\n## Communications with Agents\n\nHooks provides means to communicate with agent instances.\n\n### Bridge\n\nSee: [`use_worker_bridge`](worker::use_worker_bridge),\n[`use_reactor_bridge`](reactor::use_reactor_bridge)\n\nA bridge takes a callback to receive outputs from agents\nand provides a handle to send inputs to agents.\n\n#### Subscription\n\nSee: [`use_worker_subscription`](worker::use_worker_subscription),\n[`use_reactor_subscription`](reactor::use_reactor_subscription)\n\nSimilar to bridges, a subscription produces a handle to send inputs to agents. However, instead\nof notifying the receiver with a callback, it collect all outputs into a slice.\n\n#### Runner\n\nSee: [`use_oneshot_runner`](oneshot::use_oneshot_runner)\n\nUnlike other agents, oneshot bridges provide a `use_oneshot_runner` hook to execute oneshot\nagents on demand.\n"
  },
  {
    "path": "packages/yew-agent/src/codec.rs",
    "content": "//! Submodule providing the `Codec` trait and its default implementation using `bincode`.\n\nuse js_sys::Uint8Array;\nuse serde::{Deserialize, Serialize};\nuse wasm_bindgen::JsValue;\n\n/// Message Encoding and Decoding Format\npub trait Codec {\n    /// Encode an input to JsValue\n    fn encode<I>(input: I) -> JsValue\n    where\n        I: Serialize;\n\n    /// Decode a message to a type\n    fn decode<O>(input: JsValue) -> O\n    where\n        O: for<'de> Deserialize<'de>;\n}\n\n/// Default message encoding with [bincode].\n#[derive(Debug)]\npub struct Bincode;\n\nimpl Codec for Bincode {\n    fn encode<I>(input: I) -> JsValue\n    where\n        I: Serialize,\n    {\n        let buf = bincode::serde::encode_to_vec(&input, bincode::config::standard())\n            .expect(\"can't serialize an worker message\");\n        Uint8Array::from(buf.as_slice()).into()\n    }\n\n    fn decode<O>(input: JsValue) -> O\n    where\n        O: for<'de> Deserialize<'de>,\n    {\n        let data = Uint8Array::from(input).to_vec();\n        let (result, _) = bincode::serde::decode_from_slice(&data, bincode::config::standard())\n            .expect(\"can't deserialize an worker message\");\n        result\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/lib.rs",
    "content": "#![doc = include_str!(\"../README.md\")]\n#![deny(\n    clippy::all,\n    missing_docs,\n    missing_debug_implementations,\n    bare_trait_objects,\n    anonymous_parameters,\n    elided_lifetimes_in_paths\n)]\n\nextern crate self as yew_agent;\n\npub mod codec;\npub mod oneshot;\npub mod reactor;\npub mod worker;\npub use codec::{Bincode, Codec};\npub mod traits;\npub use traits::{Registrable, Spawnable};\n\nmod reach;\npub mod scope_ext;\n\npub use reach::Reach;\n\nmod utils;\n\n#[doc(hidden)]\npub mod __vendored {\n    pub use futures;\n}\n\npub mod prelude {\n    //! Prelude module to be imported when working with `yew-agent`.\n    //!\n    //! This module re-exports the frequently used types from the crate.\n    pub use crate::oneshot::{oneshot, use_oneshot_runner, UseOneshotRunnerHandle};\n    pub use crate::reach::Reach;\n    pub use crate::reactor::{\n        reactor, use_reactor_bridge, use_reactor_subscription, ReactorEvent, ReactorScope,\n        UseReactorBridgeHandle, UseReactorSubscriptionHandle,\n    };\n    pub use crate::scope_ext::{AgentScopeExt, ReactorBridgeHandle, WorkerBridgeHandle};\n    pub use crate::worker::{\n        use_worker_bridge, use_worker_subscription, UseWorkerBridgeHandle,\n        UseWorkerSubscriptionHandle, WorkerScope,\n    };\n    pub use crate::{Registrable, Spawnable};\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/bridge.rs",
    "content": "use futures::stream::StreamExt;\nuse pinned::mpsc;\nuse pinned::mpsc::UnboundedReceiver;\n\nuse super::traits::Oneshot;\nuse super::worker::OneshotWorker;\nuse crate::codec::Codec;\nuse crate::worker::{WorkerBridge, WorkerSpawner};\n\n/// A connection manager for components interaction with oneshot workers.\n#[derive(Debug)]\npub struct OneshotBridge<N>\nwhere\n    N: Oneshot + 'static,\n{\n    inner: WorkerBridge<OneshotWorker<N>>,\n    rx: UnboundedReceiver<N::Output>,\n}\n\nimpl<N> OneshotBridge<N>\nwhere\n    N: Oneshot + 'static,\n{\n    #[inline(always)]\n    pub(crate) fn new(\n        inner: WorkerBridge<OneshotWorker<N>>,\n        rx: UnboundedReceiver<N::Output>,\n    ) -> Self {\n        Self { inner, rx }\n    }\n\n    #[inline(always)]\n    pub(crate) fn register_callback<CODEC>(\n        spawner: &mut WorkerSpawner<OneshotWorker<N>, CODEC>,\n    ) -> UnboundedReceiver<N::Output>\n    where\n        CODEC: Codec,\n    {\n        let (tx, rx) = mpsc::unbounded();\n        spawner.callback(move |output| {\n            let _ = tx.send_now(output);\n        });\n\n        rx\n    }\n\n    /// Forks the bridge.\n    ///\n    /// This method creates a new bridge that can be used to execute tasks on the same worker\n    /// instance.\n    pub fn fork(&self) -> Self {\n        let (tx, rx) = mpsc::unbounded();\n        let inner = self.inner.fork(Some(move |output| {\n            let _ = tx.send_now(output);\n        }));\n\n        Self { inner, rx }\n    }\n\n    /// Run the current oneshot worker once in the current worker instance.\n    pub async fn run(&mut self, input: N::Input) -> N::Output {\n        // &mut self guarantees that the bridge will be\n        // exclusively borrowed during the time the oneshot worker is running.\n        self.inner.send(input);\n\n        // For each bridge, there can only be 1 active task running on the worker instance.\n        // The next output will be the output for the input that we just sent.\n        self.rx\n            .next()\n            .await\n            .expect(\"failed to receive result from worker\")\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/hooks.rs",
    "content": "use yew::prelude::*;\n\nuse super::provider::OneshotProviderState;\nuse super::Oneshot;\n\n/// Hook handle for [`use_oneshot_runner`]\n#[derive(Debug)]\npub struct UseOneshotRunnerHandle<T>\nwhere\n    T: Oneshot + 'static,\n{\n    state: OneshotProviderState<T>,\n}\n\nimpl<T> UseOneshotRunnerHandle<T>\nwhere\n    T: Oneshot + 'static,\n{\n    /// Runs an oneshot agent.\n    pub async fn run(&self, input: T::Input) -> T::Output {\n        self.state.create_bridge().run(input).await\n    }\n}\n\nimpl<T> Clone for UseOneshotRunnerHandle<T>\nwhere\n    T: Oneshot + 'static,\n{\n    fn clone(&self) -> Self {\n        Self {\n            state: self.state.clone(),\n        }\n    }\n}\n\nimpl<T> PartialEq for UseOneshotRunnerHandle<T>\nwhere\n    T: Oneshot,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.state == rhs.state\n    }\n}\n\n/// A hook to create a runner to an oneshot agent.\n#[hook]\npub fn use_oneshot_runner<T>() -> UseOneshotRunnerHandle<T>\nwhere\n    T: Oneshot + 'static,\n{\n    let state = use_context::<OneshotProviderState<T>>().expect(\"failed to find worker context\");\n\n    UseOneshotRunnerHandle { state }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/mod.rs",
    "content": "//! This module provides task agent implementation.\n\nmod bridge;\nmod hooks;\nmod provider;\nmod registrar;\nmod spawner;\nmod traits;\nmod worker;\n\npub use bridge::OneshotBridge;\npub use hooks::{use_oneshot_runner, UseOneshotRunnerHandle};\npub use provider::OneshotProvider;\npub(crate) use provider::OneshotProviderState;\npub use registrar::OneshotRegistrar;\npub use spawner::OneshotSpawner;\npub use traits::Oneshot;\n/// A procedural macro to create oneshot agents.\npub use yew_agent_macro::oneshot;\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/provider.rs",
    "content": "use core::fmt;\nuse std::any::type_name;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse serde::{Deserialize, Serialize};\nuse yew::prelude::*;\n\nuse super::{Oneshot, OneshotBridge, OneshotSpawner};\nuse crate::utils::get_next_id;\nuse crate::worker::WorkerProviderProps;\nuse crate::{Bincode, Codec, Reach};\n\npub(crate) struct OneshotProviderState<T>\nwhere\n    T: Oneshot + 'static,\n{\n    id: usize,\n    spawn_bridge_fn: Rc<dyn Fn() -> OneshotBridge<T>>,\n    reach: Reach,\n    held_bridge: Rc<RefCell<Option<OneshotBridge<T>>>>,\n}\n\nimpl<T> fmt::Debug for OneshotProviderState<T>\nwhere\n    T: Oneshot,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(type_name::<Self>())\n    }\n}\n\nimpl<T> OneshotProviderState<T>\nwhere\n    T: Oneshot,\n{\n    fn get_held_bridge(&self) -> OneshotBridge<T> {\n        let mut held_bridge = self.held_bridge.borrow_mut();\n\n        match held_bridge.as_mut() {\n            Some(m) => m.fork(),\n            None => {\n                let bridge = (self.spawn_bridge_fn)();\n                *held_bridge = Some(bridge.fork());\n                bridge\n            }\n        }\n    }\n\n    /// Creates a bridge, uses \"fork\" for public agents.\n    pub fn create_bridge(&self) -> OneshotBridge<T> {\n        match self.reach {\n            Reach::Public => {\n                let held_bridge = self.get_held_bridge();\n                held_bridge.fork()\n            }\n            Reach::Private => (self.spawn_bridge_fn)(),\n        }\n    }\n}\n\nimpl<T> Clone for OneshotProviderState<T>\nwhere\n    T: Oneshot,\n{\n    fn clone(&self) -> Self {\n        Self {\n            id: self.id,\n            spawn_bridge_fn: self.spawn_bridge_fn.clone(),\n            reach: self.reach,\n            held_bridge: self.held_bridge.clone(),\n        }\n    }\n}\n\nimpl<T> PartialEq for OneshotProviderState<T>\nwhere\n    T: Oneshot,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.id == rhs.id\n    }\n}\n\n/// The Oneshot Agent Provider.\n///\n/// This component provides its children access to an oneshot agent.\n#[component]\npub fn OneshotProvider<T, C = Bincode>(props: &WorkerProviderProps) -> Html\nwhere\n    T: Oneshot + 'static,\n    T::Input: Serialize + for<'de> Deserialize<'de> + 'static,\n    T::Output: Serialize + for<'de> Deserialize<'de> + 'static,\n    C: Codec + 'static,\n{\n    let WorkerProviderProps {\n        children,\n        path,\n        lazy,\n        module,\n        reach,\n    } = props.clone();\n\n    // Creates a spawning function so Codec is can be erased from contexts.\n    let spawn_bridge_fn: Rc<dyn Fn() -> OneshotBridge<T>> = {\n        let path = path.clone();\n        Rc::new(move || {\n            OneshotSpawner::<T>::new()\n                .as_module(module)\n                .encoding::<C>()\n                .spawn(&path)\n        })\n    };\n\n    let state = {\n        use_memo((path, lazy, reach), move |(_path, lazy, reach)| {\n            let state = OneshotProviderState::<T> {\n                id: get_next_id(),\n                spawn_bridge_fn,\n                reach: *reach,\n                held_bridge: Rc::default(),\n            };\n\n            if *reach == Reach::Public && !*lazy {\n                state.get_held_bridge();\n            }\n            state\n        })\n    };\n\n    html! {\n        <ContextProvider<OneshotProviderState<T>> context={(*state).clone()}>\n            {children}\n        </ContextProvider<OneshotProviderState<T>>>\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/registrar.rs",
    "content": "use std::fmt;\n\nuse serde::de::Deserialize;\nuse serde::ser::Serialize;\n\nuse super::traits::Oneshot;\nuse super::worker::OneshotWorker;\nuse crate::codec::{Bincode, Codec};\nuse crate::traits::Registrable;\nuse crate::worker::WorkerRegistrar;\n\n/// A registrar for oneshot workers.\npub struct OneshotRegistrar<T, CODEC = Bincode>\nwhere\n    T: Oneshot + 'static,\n    CODEC: Codec + 'static,\n{\n    inner: WorkerRegistrar<OneshotWorker<T>, CODEC>,\n}\n\nimpl<T, CODEC> Default for OneshotRegistrar<T, CODEC>\nwhere\n    T: Oneshot + 'static,\n    CODEC: Codec + 'static,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<N, CODEC> OneshotRegistrar<N, CODEC>\nwhere\n    N: Oneshot + 'static,\n    CODEC: Codec + 'static,\n{\n    /// Creates a new Oneshot Registrar.\n    pub fn new() -> Self {\n        Self {\n            inner: OneshotWorker::<N>::registrar().encoding::<CODEC>(),\n        }\n    }\n\n    /// Sets the encoding.\n    pub fn encoding<C>(&self) -> OneshotRegistrar<N, C>\n    where\n        C: Codec + 'static,\n    {\n        OneshotRegistrar {\n            inner: self.inner.encoding::<C>(),\n        }\n    }\n\n    /// Registers the worker.\n    pub fn register(&self)\n    where\n        N::Input: Serialize + for<'de> Deserialize<'de>,\n        N::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        self.inner.register()\n    }\n}\n\nimpl<T, CODEC> fmt::Debug for OneshotRegistrar<T, CODEC>\nwhere\n    T: Oneshot + 'static,\n    CODEC: Codec + 'static,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"OneshotRegistrar<_>\").finish()\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/spawner.rs",
    "content": "use serde::de::Deserialize;\nuse serde::ser::Serialize;\n\nuse super::bridge::OneshotBridge;\nuse super::traits::Oneshot;\nuse super::worker::OneshotWorker;\nuse crate::codec::{Bincode, Codec};\nuse crate::worker::WorkerSpawner;\n\n/// A spawner to create oneshot workers.\n#[derive(Debug, Default)]\npub struct OneshotSpawner<N, CODEC = Bincode>\nwhere\n    N: Oneshot + 'static,\n    CODEC: Codec,\n{\n    inner: WorkerSpawner<OneshotWorker<N>, CODEC>,\n}\n\nimpl<N, CODEC> OneshotSpawner<N, CODEC>\nwhere\n    N: Oneshot + 'static,\n    CODEC: Codec,\n{\n    /// Creates a [OneshotSpawner].\n    pub const fn new() -> Self {\n        Self {\n            inner: WorkerSpawner::<OneshotWorker<N>, CODEC>::new(),\n        }\n    }\n\n    /// Sets a new message encoding.\n    pub const fn encoding<C>(&self) -> OneshotSpawner<N, C>\n    where\n        C: Codec,\n    {\n        OneshotSpawner {\n            inner: WorkerSpawner::<OneshotWorker<N>, C>::new(),\n        }\n    }\n\n    /// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a\n    /// `path` to a loader shim script (e.g. when using Trunk, created by using\n    /// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types)\n    /// asset type) and one does not need to be generated. `false` by default.\n    pub fn with_loader(mut self, with_loader: bool) -> Self {\n        self.inner.with_loader(with_loader);\n        self\n    }\n\n    /// Determines whether the worker will be spawned with\n    /// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)\n    /// set to `module`. `true` by default.\n    ///\n    /// This option should be un-set if the worker was created with the\n    /// `--target no-modules` flag of `wasm-bindgen`. If using Trunk, see the\n    /// [`data-bindgen-target`](https://trunkrs.dev/assets/#link-asset-types)\n    /// asset type.\n    pub fn as_module(mut self, as_module: bool) -> Self {\n        self.inner.as_module(as_module);\n\n        self\n    }\n\n    /// Spawns a Oneshot Worker.\n    pub fn spawn(mut self, path: &str) -> OneshotBridge<N>\n    where\n        N::Input: Serialize + for<'de> Deserialize<'de>,\n        N::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        let rx = OneshotBridge::register_callback(&mut self.inner);\n\n        let inner = self.inner.spawn(path);\n\n        OneshotBridge::new(inner, rx)\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/traits.rs",
    "content": "use std::future::Future;\n\n/// A future-based worker that for each input, one output is produced.\npub trait Oneshot: Future {\n    /// Incoming message type.\n    type Input;\n\n    /// Creates an oneshot worker.\n    fn create(input: Self::Input) -> Self;\n}\n"
  },
  {
    "path": "packages/yew-agent/src/oneshot/worker.rs",
    "content": "use super::traits::Oneshot;\nuse crate::worker::{HandlerId, Worker, WorkerDestroyHandle, WorkerScope};\n\npub(crate) enum Message<T>\nwhere\n    T: Oneshot,\n{\n    Finished {\n        handler_id: HandlerId,\n        output: T::Output,\n    },\n}\n\npub(crate) struct OneshotWorker<T>\nwhere\n    T: 'static + Oneshot,\n{\n    running_tasks: usize,\n    destruct_handle: Option<WorkerDestroyHandle<Self>>,\n}\n\nimpl<T> Worker for OneshotWorker<T>\nwhere\n    T: 'static + Oneshot,\n{\n    type Input = T::Input;\n    type Message = Message<T>;\n    type Output = T::Output;\n\n    fn create(_scope: &WorkerScope<Self>) -> Self {\n        Self {\n            running_tasks: 0,\n            destruct_handle: None,\n        }\n    }\n\n    fn update(&mut self, scope: &WorkerScope<Self>, msg: Self::Message) {\n        let Message::Finished { handler_id, output } = msg;\n\n        self.running_tasks -= 1;\n\n        scope.respond(handler_id, output);\n\n        if self.running_tasks == 0 {\n            self.destruct_handle = None;\n        }\n    }\n\n    fn received(&mut self, scope: &WorkerScope<Self>, input: Self::Input, handler_id: HandlerId) {\n        self.running_tasks += 1;\n\n        scope.send_future(async move {\n            let output = T::create(input).await;\n\n            Message::Finished { handler_id, output }\n        });\n    }\n\n    fn destroy(&mut self, _scope: &WorkerScope<Self>, destruct: WorkerDestroyHandle<Self>) {\n        if self.running_tasks > 0 {\n            self.destruct_handle = Some(destruct);\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reach.rs",
    "content": "/// The reachability of an agent.\n#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]\npub enum Reach {\n    /// Public Reachability.\n    Public,\n    /// Private Reachability.\n    Private,\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/bridge.rs",
    "content": "use std::fmt;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures::sink::Sink;\nuse futures::stream::{FusedStream, Stream};\nuse pinned::mpsc;\nuse pinned::mpsc::{UnboundedReceiver, UnboundedSender};\nuse thiserror::Error;\n\nuse super::messages::{ReactorInput, ReactorOutput};\nuse super::scope::ReactorScoped;\nuse super::traits::Reactor;\nuse super::worker::ReactorWorker;\nuse crate::worker::{WorkerBridge, WorkerSpawner};\nuse crate::Codec;\n\n/// A connection manager for components interaction with oneshot workers.\n///\n/// As this type implements [Stream] + [Sink], it can be split with [`StreamExt::split`].\npub struct ReactorBridge<R>\nwhere\n    R: Reactor + 'static,\n{\n    inner: WorkerBridge<ReactorWorker<R>>,\n    rx: UnboundedReceiver<<R::Scope as ReactorScoped>::Output>,\n}\n\nimpl<R> fmt::Debug for ReactorBridge<R>\nwhere\n    R: Reactor,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"ReactorBridge<_>\")\n    }\n}\n\nimpl<R> ReactorBridge<R>\nwhere\n    R: Reactor + 'static,\n{\n    #[inline(always)]\n    pub(crate) fn new(\n        inner: WorkerBridge<ReactorWorker<R>>,\n        rx: UnboundedReceiver<<R::Scope as ReactorScoped>::Output>,\n    ) -> Self {\n        Self { inner, rx }\n    }\n\n    pub(crate) fn output_callback(\n        tx: &UnboundedSender<<R::Scope as ReactorScoped>::Output>,\n        output: ReactorOutput<<R::Scope as ReactorScoped>::Output>,\n    ) {\n        match output {\n            ReactorOutput::Output(m) => {\n                let _ = tx.send_now(m);\n            }\n            ReactorOutput::Finish => {\n                tx.close_now();\n            }\n        }\n    }\n\n    #[inline(always)]\n    pub(crate) fn register_callback<CODEC>(\n        spawner: &mut WorkerSpawner<ReactorWorker<R>, CODEC>,\n    ) -> UnboundedReceiver<<R::Scope as ReactorScoped>::Output>\n    where\n        CODEC: Codec,\n    {\n        let (tx, rx) = mpsc::unbounded();\n        spawner.callback(move |output| Self::output_callback(&tx, output));\n\n        rx\n    }\n\n    /// Forks the bridge.\n    ///\n    /// This method creates a new bridge connected to a new reactor on the same worker instance.\n    pub fn fork(&self) -> Self {\n        let (tx, rx) = mpsc::unbounded();\n        let inner = self\n            .inner\n            .fork(Some(move |output| Self::output_callback(&tx, output)));\n\n        Self { inner, rx }\n    }\n\n    /// Sends an input to the current reactor.\n    pub fn send_input(&self, msg: <R::Scope as ReactorScoped>::Input) {\n        self.inner.send(ReactorInput::Input(msg));\n    }\n}\n\nimpl<R> Stream for ReactorBridge<R>\nwhere\n    R: Reactor + 'static,\n{\n    type Item = <R::Scope as ReactorScoped>::Output;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        Pin::new(&mut self.rx).poll_next(cx)\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.rx.size_hint()\n    }\n}\n\nimpl<R> FusedStream for ReactorBridge<R>\nwhere\n    R: Reactor + 'static,\n{\n    fn is_terminated(&self) -> bool {\n        self.rx.is_terminated()\n    }\n}\n\n/// An error type for bridge sink.\n#[derive(Error, Clone, PartialEq, Eq, Debug)]\npub enum ReactorBridgeSinkError {\n    /// A bridge is an RAII Guard, it can only be closed by dropping the value.\n    #[error(\"attempting to close the bridge via the sink\")]\n    AttemptClosure,\n}\n\nimpl<R> Sink<<R::Scope as ReactorScoped>::Input> for ReactorBridge<R>\nwhere\n    R: Reactor + 'static,\n{\n    type Error = ReactorBridgeSinkError;\n\n    fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Poll::Ready(Err(ReactorBridgeSinkError::AttemptClosure))\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn start_send(\n        self: Pin<&mut Self>,\n        item: <R::Scope as ReactorScoped>::Input,\n    ) -> Result<(), Self::Error> {\n        self.send_input(item);\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/hooks.rs",
    "content": "use std::any::type_name;\nuse std::fmt;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse futures::sink::SinkExt;\nuse futures::stream::{SplitSink, StreamExt};\nuse wasm_bindgen::UnwrapThrowExt;\nuse yew::platform::pinned::RwLock;\nuse yew::platform::spawn_local;\nuse yew::prelude::*;\n\nuse super::provider::ReactorProviderState;\nuse super::{Reactor, ReactorBridge, ReactorScoped};\nuse crate::utils::{BridgeIdState, OutputsAction, OutputsState};\n\ntype ReactorTx<R> =\n    Rc<RwLock<SplitSink<ReactorBridge<R>, <<R as Reactor>::Scope as ReactorScoped>::Input>>>;\n\n/// A type that represents events from a reactor.\npub enum ReactorEvent<R>\nwhere\n    R: Reactor,\n{\n    /// The reactor agent has sent an output.\n    Output(<R::Scope as ReactorScoped>::Output),\n    /// The reactor agent has exited.\n    Finished,\n}\n\nimpl<R> fmt::Debug for ReactorEvent<R>\nwhere\n    R: Reactor,\n    <R::Scope as ReactorScoped>::Output: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Output(m) => f.debug_tuple(\"ReactorEvent::Output\").field(&m).finish(),\n            Self::Finished => f.debug_tuple(\"ReactorEvent::Finished\").finish(),\n        }\n    }\n}\n\n/// Hook handle for the [`use_reactor_bridge`] hook.\npub struct UseReactorBridgeHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    tx: ReactorTx<R>,\n    ctr: UseReducerDispatcher<BridgeIdState>,\n}\n\nimpl<R> fmt::Debug for UseReactorBridgeHandle<R>\nwhere\n    R: 'static + Reactor,\n    <R::Scope as ReactorScoped>::Input: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(type_name::<Self>())\n            .field(\"inner\", &self.tx)\n            .finish()\n    }\n}\n\nimpl<R> Clone for UseReactorBridgeHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    fn clone(&self) -> Self {\n        Self {\n            tx: self.tx.clone(),\n            ctr: self.ctr.clone(),\n        }\n    }\n}\n\nimpl<R> UseReactorBridgeHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    /// Send an input to a reactor agent.\n    pub fn send(&self, msg: <R::Scope as ReactorScoped>::Input) {\n        let tx = self.tx.clone();\n        spawn_local(async move {\n            let mut tx = tx.write().await;\n            let _ = tx.send(msg).await;\n        });\n    }\n\n    /// Reset the bridge.\n    ///\n    /// Disconnect the old bridge and re-connects the agent with a new bridge.\n    pub fn reset(&self) {\n        self.ctr.dispatch(());\n    }\n}\n\nimpl<R> PartialEq for UseReactorBridgeHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.ctr == rhs.ctr\n    }\n}\n\n/// A hook to bridge to a [`Reactor`].\n///\n/// This hooks will only bridge the reactor once over the entire component lifecycle.\n///\n/// Takes a callback as the argument.\n///\n/// The callback will be updated on every render to make sure captured values (if any) are up to\n/// date.\n#[hook]\npub fn use_reactor_bridge<R, F>(on_output: F) -> UseReactorBridgeHandle<R>\nwhere\n    R: 'static + Reactor,\n    F: Fn(ReactorEvent<R>) + 'static,\n{\n    let ctr = use_reducer(BridgeIdState::default);\n\n    let worker_state = use_context::<ReactorProviderState<R>>()\n        .expect_throw(\"cannot find a provider for current agent.\");\n\n    let on_output = Rc::new(on_output);\n\n    let on_output_ref = {\n        let on_output = on_output.clone();\n        use_mut_ref(move || on_output)\n    };\n\n    // Refresh the callback on every render.\n    {\n        let mut on_output_ref = on_output_ref.borrow_mut();\n        *on_output_ref = on_output;\n    }\n\n    let tx = use_memo((worker_state, ctr.inner), |(state, _ctr)| {\n        let bridge = state.create_bridge();\n\n        let (tx, mut rx) = bridge.split();\n\n        spawn_local(async move {\n            while let Some(m) = rx.next().await {\n                let on_output = on_output_ref.borrow().clone();\n                on_output(ReactorEvent::<R>::Output(m));\n            }\n\n            let on_output = on_output_ref.borrow().clone();\n            on_output(ReactorEvent::<R>::Finished);\n        });\n\n        RwLock::new(tx)\n    });\n\n    UseReactorBridgeHandle {\n        tx: tx.clone(),\n        ctr: ctr.dispatcher(),\n    }\n}\n\n/// Hook handle for the [`use_reactor_subscription`] hook.\npub struct UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    bridge: UseReactorBridgeHandle<R>,\n    outputs: Vec<Rc<<R::Scope as ReactorScoped>::Output>>,\n    finished: bool,\n    ctr: usize,\n}\n\nimpl<R> UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    /// Send an input to a reactor agent.\n    pub fn send(&self, msg: <R::Scope as ReactorScoped>::Input) {\n        self.bridge.send(msg);\n    }\n\n    /// Returns whether the current bridge has received a finish message.\n    pub fn finished(&self) -> bool {\n        self.finished\n    }\n\n    /// Reset the subscription.\n    ///\n    /// This disconnects the old bridge and re-connects the agent with a new bridge.\n    /// Existing outputs stored in the subscription will also be cleared.\n    pub fn reset(&self) {\n        self.bridge.reset();\n    }\n}\n\nimpl<R> Clone for UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    fn clone(&self) -> Self {\n        Self {\n            bridge: self.bridge.clone(),\n            outputs: self.outputs.clone(),\n            ctr: self.ctr,\n            finished: self.finished,\n        }\n    }\n}\n\nimpl<R> fmt::Debug for UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n    <R::Scope as ReactorScoped>::Input: fmt::Debug,\n    <R::Scope as ReactorScoped>::Output: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(type_name::<Self>())\n            .field(\"bridge\", &self.bridge)\n            .field(\"outputs\", &self.outputs)\n            .finish()\n    }\n}\n\nimpl<R> Deref for UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    type Target = [Rc<<R::Scope as ReactorScoped>::Output>];\n\n    fn deref(&self) -> &Self::Target {\n        &self.outputs\n    }\n}\n\nimpl<R> PartialEq for UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.bridge == rhs.bridge && self.ctr == rhs.ctr\n    }\n}\n\n/// A hook to subscribe to the outputs of a [Reactor] agent.\n///\n/// All outputs sent to current bridge will be collected into a slice.\n#[hook]\npub fn use_reactor_subscription<R>() -> UseReactorSubscriptionHandle<R>\nwhere\n    R: 'static + Reactor,\n{\n    let outputs = use_reducer(OutputsState::<<R::Scope as ReactorScoped>::Output>::default);\n\n    let bridge = {\n        let outputs = outputs.clone();\n        use_reactor_bridge::<R, _>(move |output| {\n            outputs.dispatch(match output {\n                ReactorEvent::Output(m) => OutputsAction::Push(m.into()),\n                ReactorEvent::Finished => OutputsAction::Close,\n            })\n        })\n    };\n\n    {\n        let outputs = outputs.clone();\n        use_effect_with(bridge.clone(), move |_| {\n            outputs.dispatch(OutputsAction::Reset);\n\n            || {}\n        });\n    }\n\n    UseReactorSubscriptionHandle {\n        bridge,\n        outputs: outputs.inner.clone(),\n        ctr: outputs.ctr,\n        finished: outputs.closed,\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/messages.rs",
    "content": "use serde::{Deserialize, Serialize};\n\n/// The Bridge Input.\n#[derive(Debug, Serialize, Deserialize)]\npub(crate) enum ReactorInput<I> {\n    /// An input message.\n    Input(I),\n}\n\n/// The Bridge Output.\n#[derive(Debug, Serialize, Deserialize)]\npub enum ReactorOutput<O> {\n    /// An output message has been received.\n    Output(O),\n    /// Reactor for current bridge has exited.\n    Finish,\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/mod.rs",
    "content": "//! This module contains the reactor agent implementation.\n//!\n//! Reactor agents are agents that receive multiple inputs and send multiple outputs over a single\n//! bridge. A reactor is defined as an async function that takes a [ReactorScope]\n//! as the argument.\n//!\n//! The reactor scope is a stream that produces inputs from the bridge and a\n//! sink that implements an additional send method to send outputs to the connected bridge.\n//! When the bridge disconnects, the output stream and input sink will be closed.\n//!\n//! # Example\n//!\n//! ```\n//! # use serde::{Serialize, Deserialize};\n//! # #[derive(Serialize, Deserialize)]\n//! # pub struct ReactorInput {}\n//! # #[derive(Serialize, Deserialize)]\n//! # pub struct ReactorOutput {}\n//! #\n//! use futures::sink::SinkExt;\n//! use futures::stream::StreamExt;\n//! use yew_agent::reactor::{reactor, ReactorScope};\n//! #[reactor(MyReactor)]\n//! pub async fn my_reactor(mut scope: ReactorScope<ReactorInput, ReactorOutput>) {\n//!     while let Some(input) = scope.next().await {\n//!         // handles each input.\n//!         // ...\n//! #       let output = ReactorOutput { /* ... */ };\n//!\n//!         // sends output\n//!         if scope.send(output).await.is_err() {\n//!             // sender closed, the bridge is disconnected\n//!             break;\n//!         }\n//!     }\n//! }\n//! ```\n\nmod bridge;\nmod hooks;\nmod messages;\nmod provider;\nmod registrar;\nmod scope;\nmod spawner;\nmod traits;\nmod worker;\n\npub use bridge::{ReactorBridge, ReactorBridgeSinkError};\npub use hooks::{\n    use_reactor_bridge, use_reactor_subscription, ReactorEvent, UseReactorBridgeHandle,\n    UseReactorSubscriptionHandle,\n};\npub use provider::ReactorProvider;\npub(crate) use provider::ReactorProviderState;\npub use registrar::ReactorRegistrar;\npub use scope::{ReactorScope, ReactorScoped};\npub use spawner::ReactorSpawner;\npub use traits::Reactor;\n/// A procedural macro to create reactor agents.\npub use yew_agent_macro::reactor;\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/provider.rs",
    "content": "use std::any::type_name;\nuse std::cell::RefCell;\nuse std::fmt;\nuse std::rc::Rc;\n\nuse serde::{Deserialize, Serialize};\nuse yew::prelude::*;\n\nuse super::{Reactor, ReactorBridge, ReactorScoped, ReactorSpawner};\nuse crate::utils::get_next_id;\nuse crate::worker::WorkerProviderProps;\nuse crate::{Bincode, Codec, Reach};\n\npub(crate) struct ReactorProviderState<T>\nwhere\n    T: Reactor + 'static,\n{\n    id: usize,\n    spawn_bridge_fn: Rc<dyn Fn() -> ReactorBridge<T>>,\n    reach: Reach,\n    held_bridge: Rc<RefCell<Option<ReactorBridge<T>>>>,\n}\n\nimpl<T> fmt::Debug for ReactorProviderState<T>\nwhere\n    T: Reactor,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(type_name::<Self>())\n    }\n}\n\nimpl<T> ReactorProviderState<T>\nwhere\n    T: Reactor,\n{\n    fn get_held_bridge(&self) -> ReactorBridge<T> {\n        let mut held_bridge = self.held_bridge.borrow_mut();\n\n        match held_bridge.as_mut() {\n            Some(m) => m.fork(),\n            None => {\n                let bridge = (self.spawn_bridge_fn)();\n                *held_bridge = Some(bridge.fork());\n                bridge\n            }\n        }\n    }\n\n    /// Creates a bridge, uses \"fork\" for public agents.\n    pub fn create_bridge(&self) -> ReactorBridge<T> {\n        match self.reach {\n            Reach::Public => {\n                let held_bridge = self.get_held_bridge();\n                held_bridge.fork()\n            }\n            Reach::Private => (self.spawn_bridge_fn)(),\n        }\n    }\n}\n\nimpl<T> Clone for ReactorProviderState<T>\nwhere\n    T: Reactor,\n{\n    fn clone(&self) -> Self {\n        Self {\n            id: self.id,\n            spawn_bridge_fn: self.spawn_bridge_fn.clone(),\n            reach: self.reach,\n            held_bridge: self.held_bridge.clone(),\n        }\n    }\n}\n\nimpl<T> PartialEq for ReactorProviderState<T>\nwhere\n    T: Reactor,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.id == rhs.id\n    }\n}\n\n/// The Reactor Agent Provider.\n///\n/// This component provides its children access to a reactor agent.\n#[component]\npub fn ReactorProvider<R, C = Bincode>(props: &WorkerProviderProps) -> Html\nwhere\n    R: 'static + Reactor,\n    <<R as Reactor>::Scope as ReactorScoped>::Input:\n        Serialize + for<'de> Deserialize<'de> + 'static,\n    <<R as Reactor>::Scope as ReactorScoped>::Output:\n        Serialize + for<'de> Deserialize<'de> + 'static,\n    C: Codec + 'static,\n{\n    let WorkerProviderProps {\n        children,\n        path,\n        lazy,\n        module,\n        reach,\n    } = props.clone();\n\n    // Creates a spawning function so Codec is can be erased from contexts.\n    let spawn_bridge_fn: Rc<dyn Fn() -> ReactorBridge<R>> = {\n        let path = path.clone();\n        Rc::new(move || {\n            ReactorSpawner::<R>::new()\n                .as_module(module)\n                .encoding::<C>()\n                .spawn(&path)\n        })\n    };\n\n    let state = {\n        use_memo((path, lazy, reach), move |(_path, lazy, reach)| {\n            let state = ReactorProviderState::<R> {\n                id: get_next_id(),\n                spawn_bridge_fn,\n                reach: *reach,\n                held_bridge: Rc::default(),\n            };\n\n            if *reach == Reach::Public && !*lazy {\n                state.get_held_bridge();\n            }\n            state\n        })\n    };\n\n    html! {\n        <ContextProvider<ReactorProviderState<R>> context={(*state).clone()}>\n            {children}\n        </ContextProvider<ReactorProviderState<R>>>\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/registrar.rs",
    "content": "use std::fmt;\n\nuse serde::de::Deserialize;\nuse serde::ser::Serialize;\n\nuse super::scope::ReactorScoped;\nuse super::traits::Reactor;\nuse super::worker::ReactorWorker;\nuse crate::codec::{Bincode, Codec};\nuse crate::traits::Registrable;\nuse crate::worker::WorkerRegistrar;\n\n/// A registrar for reactor workers.\npub struct ReactorRegistrar<R, CODEC = Bincode>\nwhere\n    R: Reactor + 'static,\n    CODEC: Codec + 'static,\n{\n    inner: WorkerRegistrar<ReactorWorker<R>, CODEC>,\n}\n\nimpl<R, CODEC> Default for ReactorRegistrar<R, CODEC>\nwhere\n    R: Reactor + 'static,\n    CODEC: Codec + 'static,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<R, CODEC> ReactorRegistrar<R, CODEC>\nwhere\n    R: Reactor + 'static,\n    CODEC: Codec + 'static,\n{\n    /// Creates a new reactor registrar.\n    pub fn new() -> Self {\n        Self {\n            inner: ReactorWorker::<R>::registrar().encoding::<CODEC>(),\n        }\n    }\n\n    /// Sets the encoding.\n    pub fn encoding<C>(&self) -> ReactorRegistrar<R, C>\n    where\n        C: Codec + 'static,\n    {\n        ReactorRegistrar {\n            inner: self.inner.encoding::<C>(),\n        }\n    }\n\n    /// Registers the worker.\n    pub fn register(&self)\n    where\n        <R::Scope as ReactorScoped>::Input: Serialize + for<'de> Deserialize<'de>,\n        <R::Scope as ReactorScoped>::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        self.inner.register()\n    }\n}\n\nimpl<R, CODEC> fmt::Debug for ReactorRegistrar<R, CODEC>\nwhere\n    R: Reactor + 'static,\n    CODEC: Codec + 'static,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ReactorRegistrar<_>\").finish()\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/scope.rs",
    "content": "use std::convert::Infallible;\nuse std::fmt;\nuse std::pin::Pin;\n\nuse futures::stream::{FusedStream, Stream};\nuse futures::task::{Context, Poll};\nuse futures::Sink;\n\n/// A handle to communicate with bridges.\npub struct ReactorScope<I, O> {\n    input_stream: Pin<Box<dyn FusedStream<Item = I>>>,\n    output_sink: Pin<Box<dyn Sink<O, Error = Infallible>>>,\n}\n\nimpl<I, O> fmt::Debug for ReactorScope<I, O> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ReactorScope<_>\").finish()\n    }\n}\n\nimpl<I, O> Stream for ReactorScope<I, O> {\n    type Item = I;\n\n    #[inline(always)]\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        Pin::new(&mut self.input_stream).poll_next(cx)\n    }\n\n    #[inline(always)]\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.input_stream.size_hint()\n    }\n}\n\nimpl<I, O> FusedStream for ReactorScope<I, O> {\n    #[inline(always)]\n    fn is_terminated(&self) -> bool {\n        self.input_stream.is_terminated()\n    }\n}\n\n/// A helper trait to extract the input and output type from a [ReactorStream].\npub trait ReactorScoped: Stream + FusedStream {\n    /// The Input Message.\n    type Input;\n    /// The Output Message.\n    type Output;\n\n    /// Creates a ReactorReceiver.\n    fn new<IS, OS>(input_stream: IS, output_sink: OS) -> Self\n    where\n        IS: Stream<Item = Self::Input> + FusedStream + 'static,\n        OS: Sink<Self::Output, Error = Infallible> + 'static;\n}\n\nimpl<I, O> ReactorScoped for ReactorScope<I, O> {\n    type Input = I;\n    type Output = O;\n\n    #[inline]\n    fn new<IS, OS>(input_stream: IS, output_sink: OS) -> Self\n    where\n        IS: Stream<Item = Self::Input> + FusedStream + 'static,\n        OS: Sink<Self::Output, Error = Infallible> + 'static,\n    {\n        Self {\n            input_stream: Box::pin(input_stream),\n            output_sink: Box::pin(output_sink),\n        }\n    }\n}\n\nimpl<I, O> Sink<O> for ReactorScope<I, O> {\n    type Error = Infallible;\n\n    fn start_send(mut self: Pin<&mut Self>, item: O) -> Result<(), Self::Error> {\n        Pin::new(&mut self.output_sink).start_send(item)\n    }\n\n    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Pin::new(&mut self.output_sink).poll_close(cx)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Pin::new(&mut self.output_sink).poll_flush(cx)\n    }\n\n    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Pin::new(&mut self.output_sink).poll_flush(cx)\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/spawner.rs",
    "content": "use serde::de::Deserialize;\nuse serde::ser::Serialize;\n\nuse super::bridge::ReactorBridge;\nuse super::scope::ReactorScoped;\nuse super::traits::Reactor;\nuse super::worker::ReactorWorker;\nuse crate::codec::{Bincode, Codec};\nuse crate::worker::WorkerSpawner;\n\n/// A spawner to create oneshot workers.\n#[derive(Debug, Default)]\npub struct ReactorSpawner<R, CODEC = Bincode>\nwhere\n    R: Reactor + 'static,\n    CODEC: Codec,\n{\n    inner: WorkerSpawner<ReactorWorker<R>, CODEC>,\n}\n\nimpl<R, CODEC> ReactorSpawner<R, CODEC>\nwhere\n    R: Reactor + 'static,\n    CODEC: Codec,\n{\n    /// Creates a ReactorSpawner.\n    pub const fn new() -> Self {\n        Self {\n            inner: WorkerSpawner::<ReactorWorker<R>, CODEC>::new(),\n        }\n    }\n\n    /// Sets a new message encoding.\n    pub const fn encoding<C>(&self) -> ReactorSpawner<R, C>\n    where\n        C: Codec,\n    {\n        ReactorSpawner {\n            inner: WorkerSpawner::<ReactorWorker<R>, C>::new(),\n        }\n    }\n\n    /// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a\n    /// `path` to a loader shim script (e.g. when using Trunk, created by using\n    /// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types)\n    /// asset type) and one does not need to be generated. `false` by default.\n    pub fn with_loader(mut self, with_loader: bool) -> Self {\n        self.inner.with_loader(with_loader);\n        self\n    }\n\n    /// Determines whether the worker will be spawned with\n    /// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)\n    /// set to `module`. `true` by default.\n    ///\n    /// This option should be un-set if the worker was created with the\n    /// `--target no-modules` flag of `wasm-bindgen`. If using Trunk, see the\n    /// [`data-bindgen-target`](https://trunkrs.dev/assets/#link-asset-types)\n    /// asset type.\n    pub fn as_module(mut self, as_module: bool) -> Self {\n        self.inner.as_module(as_module);\n\n        self\n    }\n\n    /// Spawns a reactor worker.\n    pub fn spawn(mut self, path: &str) -> ReactorBridge<R>\n    where\n        <R::Scope as ReactorScoped>::Input: Serialize + for<'de> Deserialize<'de>,\n        <R::Scope as ReactorScoped>::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        let rx = ReactorBridge::register_callback(&mut self.inner);\n\n        let inner = self.inner.spawn(path);\n\n        ReactorBridge::new(inner, rx)\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/traits.rs",
    "content": "use std::future::Future;\n\nuse super::scope::ReactorScoped;\n\n/// A reactor worker.\npub trait Reactor: Future<Output = ()> {\n    /// The Reactor Scope\n    type Scope: ReactorScoped;\n\n    /// Creates a reactor worker.\n    fn create(scope: Self::Scope) -> Self;\n}\n"
  },
  {
    "path": "packages/yew-agent/src/reactor/worker.rs",
    "content": "use std::collections::HashMap;\nuse std::convert::Infallible;\n\nuse futures::sink;\nuse futures::stream::StreamExt;\nuse pinned::mpsc;\nuse pinned::mpsc::UnboundedSender;\nuse wasm_bindgen_futures::spawn_local;\n\nuse super::messages::{ReactorInput, ReactorOutput};\nuse super::scope::ReactorScoped;\nuse super::traits::Reactor;\nuse crate::worker::{HandlerId, Worker, WorkerDestroyHandle, WorkerScope};\n\npub(crate) enum Message {\n    ReactorExited(HandlerId),\n}\n\npub(crate) struct ReactorWorker<R>\nwhere\n    R: 'static + Reactor,\n{\n    senders: HashMap<HandlerId, UnboundedSender<<R::Scope as ReactorScoped>::Input>>,\n    destruct_handle: Option<WorkerDestroyHandle<Self>>,\n}\n\nimpl<R> Worker for ReactorWorker<R>\nwhere\n    R: 'static + Reactor,\n{\n    type Input = ReactorInput<<R::Scope as ReactorScoped>::Input>;\n    type Message = Message;\n    type Output = ReactorOutput<<R::Scope as ReactorScoped>::Output>;\n\n    fn create(_scope: &WorkerScope<Self>) -> Self {\n        Self {\n            senders: HashMap::new(),\n            destruct_handle: None,\n        }\n    }\n\n    fn update(&mut self, scope: &WorkerScope<Self>, msg: Self::Message) {\n        match msg {\n            Self::Message::ReactorExited(id) => {\n                scope.respond(id, ReactorOutput::Finish);\n                self.senders.remove(&id);\n            }\n        }\n\n        // All reactors have closed themselves, the worker can now close.\n        if self.destruct_handle.is_some() && self.senders.is_empty() {\n            self.destruct_handle = None;\n        }\n    }\n\n    fn connected(&mut self, scope: &WorkerScope<Self>, id: HandlerId) {\n        let from_bridge = {\n            let (tx, rx) = mpsc::unbounded();\n            self.senders.insert(id, tx);\n\n            rx\n        };\n\n        let to_bridge = {\n            let scope_ = scope.clone();\n            let (tx, mut rx) = mpsc::unbounded();\n            spawn_local(async move {\n                while let Some(m) = rx.next().await {\n                    scope_.respond(id, ReactorOutput::Output(m));\n                }\n            });\n\n            sink::unfold((), move |_, item: <R::Scope as ReactorScoped>::Output| {\n                let tx = tx.clone();\n\n                async move {\n                    let _ = tx.send_now(item);\n\n                    Ok::<(), Infallible>(())\n                }\n            })\n        };\n\n        let reactor_scope = ReactorScoped::new(from_bridge, to_bridge);\n\n        let reactor = R::create(reactor_scope);\n\n        scope.send_future(async move {\n            reactor.await;\n\n            Message::ReactorExited(id)\n        });\n    }\n\n    fn received(&mut self, _scope: &WorkerScope<Self>, input: Self::Input, id: HandlerId) {\n        match input {\n            Self::Input::Input(input) => {\n                if let Some(m) = self.senders.get_mut(&id) {\n                    let _result = m.send_now(input);\n                }\n            }\n        }\n    }\n\n    fn disconnected(&mut self, _scope: &WorkerScope<Self>, id: HandlerId) {\n        // We close this channel, but drop it when the reactor has exited itself.\n        if let Some(m) = self.senders.get_mut(&id) {\n            m.close_now();\n        }\n    }\n\n    fn destroy(&mut self, _scope: &WorkerScope<Self>, destruct: WorkerDestroyHandle<Self>) {\n        if !self.senders.is_empty() {\n            self.destruct_handle = Some(destruct);\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/scope_ext.rs",
    "content": "//! This module contains extensions to the component scope for agent access.\n\nuse std::any::type_name;\nuse std::fmt;\nuse std::rc::Rc;\n\nuse futures::stream::SplitSink;\nuse futures::{SinkExt, StreamExt};\nuse wasm_bindgen::UnwrapThrowExt;\nuse yew::html::Scope;\nuse yew::platform::pinned::RwLock;\nuse yew::platform::spawn_local;\nuse yew::prelude::*;\n\nuse crate::oneshot::{Oneshot, OneshotProviderState};\nuse crate::reactor::{Reactor, ReactorBridge, ReactorEvent, ReactorProviderState, ReactorScoped};\nuse crate::worker::{Worker, WorkerBridge, WorkerProviderState};\n\n/// A Worker Bridge Handle.\n#[derive(Debug)]\npub struct WorkerBridgeHandle<W>\nwhere\n    W: Worker,\n{\n    inner: WorkerBridge<W>,\n}\n\nimpl<W> WorkerBridgeHandle<W>\nwhere\n    W: Worker,\n{\n    /// Sends a message to the worker agent.\n    pub fn send(&self, input: W::Input) {\n        self.inner.send(input)\n    }\n}\n\ntype ReactorTx<R> =\n    Rc<RwLock<SplitSink<ReactorBridge<R>, <<R as Reactor>::Scope as ReactorScoped>::Input>>>;\n\n/// A Reactor Bridge Handle.\npub struct ReactorBridgeHandle<R>\nwhere\n    R: Reactor + 'static,\n{\n    tx: ReactorTx<R>,\n}\n\nimpl<R> fmt::Debug for ReactorBridgeHandle<R>\nwhere\n    R: Reactor + 'static,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(type_name::<Self>()).finish_non_exhaustive()\n    }\n}\n\nimpl<R> ReactorBridgeHandle<R>\nwhere\n    R: Reactor + 'static,\n{\n    /// Sends a message to the reactor agent.\n    pub fn send(&self, input: <R::Scope as ReactorScoped>::Input) {\n        let tx = self.tx.clone();\n        spawn_local(async move {\n            let mut tx = tx.write().await;\n            let _ = tx.send(input).await;\n        });\n    }\n}\n\n/// An extension to [`Scope`](yew::html::Scope) that provides communication mechanism to agents.\n///\n/// You can access them on `ctx.link()`\npub trait AgentScopeExt {\n    /// Bridges to a Worker Agent.\n    fn bridge_worker<W>(&self, callback: Callback<W::Output>) -> WorkerBridgeHandle<W>\n    where\n        W: Worker + 'static;\n\n    /// Bridges to a Reactor Agent.\n    fn bridge_reactor<R>(&self, callback: Callback<ReactorEvent<R>>) -> ReactorBridgeHandle<R>\n    where\n        R: Reactor + 'static,\n        <R::Scope as ReactorScoped>::Output: 'static;\n\n    /// Runs an oneshot in an Oneshot Agent.\n    fn run_oneshot<T>(&self, input: T::Input, callback: Callback<T::Output>)\n    where\n        T: Oneshot + 'static;\n}\n\nimpl<COMP> AgentScopeExt for Scope<COMP>\nwhere\n    COMP: Component,\n{\n    fn bridge_worker<W>(&self, callback: Callback<W::Output>) -> WorkerBridgeHandle<W>\n    where\n        W: Worker + 'static,\n    {\n        let inner = self\n            .context::<Rc<WorkerProviderState<W>>>((|_| {}).into())\n            .expect_throw(\"failed to bridge to agent.\")\n            .0\n            .create_bridge(callback);\n\n        WorkerBridgeHandle { inner }\n    }\n\n    fn bridge_reactor<R>(&self, callback: Callback<ReactorEvent<R>>) -> ReactorBridgeHandle<R>\n    where\n        R: Reactor + 'static,\n        <R::Scope as ReactorScoped>::Output: 'static,\n    {\n        let (tx, mut rx) = self\n            .context::<ReactorProviderState<R>>((|_| {}).into())\n            .expect_throw(\"failed to bridge to agent.\")\n            .0\n            .create_bridge()\n            .split();\n\n        spawn_local(async move {\n            while let Some(m) = rx.next().await {\n                callback.emit(ReactorEvent::<R>::Output(m));\n            }\n\n            callback.emit(ReactorEvent::<R>::Finished);\n        });\n\n        let tx = Rc::new(RwLock::new(tx));\n\n        ReactorBridgeHandle { tx }\n    }\n\n    fn run_oneshot<T>(&self, input: T::Input, callback: Callback<T::Output>)\n    where\n        T: Oneshot + 'static,\n    {\n        let (inner, _) = self\n            .context::<OneshotProviderState<T>>((|_| {}).into())\n            .expect_throw(\"failed to bridge to agent.\");\n\n        spawn_local(async move { callback.emit(inner.create_bridge().run(input).await) });\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/traits.rs",
    "content": "//! Submodule providing the `Spawnable` and `Registrable` traits.\n\n/// A Worker that can be spawned by a spawner.\npub trait Spawnable {\n    /// Spawner Type.\n    type Spawner;\n\n    /// Creates a spawner.\n    fn spawner() -> Self::Spawner;\n}\n\n/// A trait to enable public workers being registered in a web worker.\npub trait Registrable {\n    /// Registrar Type.\n    type Registrar;\n\n    /// Creates a registrar for the current worker.\n    fn registrar() -> Self::Registrar;\n}\n"
  },
  {
    "path": "packages/yew-agent/src/utils.rs",
    "content": "use std::rc::Rc;\nuse std::sync::atomic::{AtomicUsize, Ordering};\n\nuse wasm_bindgen::UnwrapThrowExt;\nuse yew::Reducible;\n\n/// Convenience function to avoid repeating expect logic.\npub fn window() -> web_sys::Window {\n    web_sys::window().expect_throw(\"Can't find the global Window\")\n}\n\n/// Gets a unique worker id\npub(crate) fn get_next_id() -> usize {\n    static CTR: AtomicUsize = AtomicUsize::new(0);\n\n    CTR.fetch_add(1, Ordering::SeqCst)\n}\n\n#[derive(Default, PartialEq)]\npub(crate) struct BridgeIdState {\n    pub inner: usize,\n}\n\nimpl Reducible for BridgeIdState {\n    type Action = ();\n\n    fn reduce(self: Rc<Self>, _: Self::Action) -> Rc<Self> {\n        Self {\n            inner: self.inner + 1,\n        }\n        .into()\n    }\n}\n\npub(crate) enum OutputsAction<T> {\n    Push(Rc<T>),\n    Close,\n    Reset,\n}\n\npub(crate) struct OutputsState<T> {\n    pub ctr: usize,\n    pub inner: Vec<Rc<T>>,\n    pub closed: bool,\n}\n\nimpl<T> Clone for OutputsState<T> {\n    fn clone(&self) -> Self {\n        Self {\n            ctr: self.ctr,\n            inner: self.inner.clone(),\n            closed: self.closed,\n        }\n    }\n}\n\nimpl<T> Reducible for OutputsState<T> {\n    type Action = OutputsAction<T>;\n\n    fn reduce(mut self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        {\n            let this = Rc::make_mut(&mut self);\n            this.ctr += 1;\n\n            match action {\n                OutputsAction::Push(m) => this.inner.push(m),\n                OutputsAction::Close => {\n                    this.closed = true;\n                }\n                OutputsAction::Reset => {\n                    this.closed = false;\n                    this.inner = Vec::new();\n                }\n            }\n        }\n\n        self\n    }\n}\n\nimpl<T> Default for OutputsState<T> {\n    fn default() -> Self {\n        Self {\n            ctr: 0,\n            inner: Vec::new(),\n            closed: false,\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/bridge.rs",
    "content": "use std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::fmt;\nuse std::marker::PhantomData;\nuse std::rc::{Rc, Weak};\n\nuse serde::{Deserialize, Serialize};\n\nuse super::handler_id::HandlerId;\nuse super::messages::ToWorker;\nuse super::native_worker::NativeWorkerExt;\nuse super::traits::Worker;\nuse super::{Callback, Shared};\nuse crate::codec::Codec;\n\npub(crate) type ToWorkerQueue<W> = Vec<ToWorker<W>>;\npub(crate) type CallbackMap<W> = HashMap<HandlerId, Weak<dyn Fn(<W as Worker>::Output)>>;\n\nstruct WorkerBridgeInner<W>\nwhere\n    W: Worker,\n{\n    // When worker is loaded, queue becomes None.\n    pending_queue: Shared<Option<ToWorkerQueue<W>>>,\n    callbacks: Shared<CallbackMap<W>>,\n    post_msg: Rc<dyn Fn(ToWorker<W>)>,\n}\n\nimpl<W> fmt::Debug for WorkerBridgeInner<W>\nwhere\n    W: Worker,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"WorkerBridgeInner<_>\")\n    }\n}\n\nimpl<W> WorkerBridgeInner<W>\nwhere\n    W: Worker,\n{\n    /// Send a message to the worker, queuing the message if necessary\n    fn send_message(&self, msg: ToWorker<W>) {\n        let mut pending_queue = self.pending_queue.borrow_mut();\n\n        match pending_queue.as_mut() {\n            Some(m) => {\n                m.push(msg);\n            }\n            None => {\n                (self.post_msg)(msg);\n            }\n        }\n    }\n}\n\nimpl<W> Drop for WorkerBridgeInner<W>\nwhere\n    W: Worker,\n{\n    fn drop(&mut self) {\n        let destroy = ToWorker::Destroy;\n        self.send_message(destroy);\n    }\n}\n\n/// A connection manager for components interaction with workers.\npub struct WorkerBridge<W>\nwhere\n    W: Worker,\n{\n    inner: Rc<WorkerBridgeInner<W>>,\n    id: HandlerId,\n    _worker: PhantomData<W>,\n    _cb: Option<Rc<dyn Fn(W::Output)>>,\n}\n\nimpl<W> WorkerBridge<W>\nwhere\n    W: Worker,\n{\n    fn init(&self) {\n        self.inner.send_message(ToWorker::Connected(self.id));\n    }\n\n    pub(crate) fn new<CODEC>(\n        id: HandlerId,\n        native_worker: web_sys::Worker,\n        pending_queue: Rc<RefCell<Option<ToWorkerQueue<W>>>>,\n        callbacks: Rc<RefCell<CallbackMap<W>>>,\n        callback: Option<Callback<W::Output>>,\n    ) -> Self\n    where\n        CODEC: Codec,\n        W::Input: Serialize + for<'de> Deserialize<'de>,\n    {\n        let post_msg = move |msg: ToWorker<W>| native_worker.post_packed_message::<_, CODEC>(msg);\n\n        let self_ = Self {\n            inner: WorkerBridgeInner {\n                pending_queue,\n                callbacks,\n                post_msg: Rc::new(post_msg),\n            }\n            .into(),\n            id,\n            _worker: PhantomData,\n            _cb: callback,\n        };\n        self_.init();\n\n        self_\n    }\n\n    /// Send a message to the current worker.\n    pub fn send(&self, msg: W::Input) {\n        let msg = ToWorker::ProcessInput(self.id, msg);\n        self.inner.send_message(msg);\n    }\n\n    /// Forks the bridge with a different callback.\n    ///\n    /// This creates a new [HandlerID] that helps the worker to differentiate bridges.\n    pub fn fork<F>(&self, cb: Option<F>) -> Self\n    where\n        F: 'static + Fn(W::Output),\n    {\n        let cb = cb.map(|m| Rc::new(m) as Rc<dyn Fn(W::Output)>);\n        let handler_id = HandlerId::new();\n\n        if let Some(cb_weak) = cb.as_ref().map(Rc::downgrade) {\n            self.inner\n                .callbacks\n                .borrow_mut()\n                .insert(handler_id, cb_weak);\n        }\n\n        let self_ = Self {\n            inner: self.inner.clone(),\n            id: handler_id,\n            _worker: PhantomData,\n            _cb: cb,\n        };\n        self_.init();\n\n        self_\n    }\n}\n\nimpl<W> Drop for WorkerBridge<W>\nwhere\n    W: Worker,\n{\n    fn drop(&mut self) {\n        let disconnected = ToWorker::Disconnected(self.id);\n        self.inner.send_message(disconnected);\n    }\n}\n\nimpl<W> fmt::Debug for WorkerBridge<W>\nwhere\n    W: Worker,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"WorkerBridge<_>\")\n    }\n}\n\nimpl<W> PartialEq for WorkerBridge<W>\nwhere\n    W: Worker,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.id == rhs.id\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/handler_id.rs",
    "content": "use std::sync::atomic::{AtomicUsize, Ordering};\n\nuse serde::{Deserialize, Serialize};\n\n/// Identifier to send output to bridges.\n#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Clone, Copy)]\npub struct HandlerId(usize);\n\nimpl HandlerId {\n    pub(crate) fn new() -> Self {\n        static CTR: AtomicUsize = AtomicUsize::new(0);\n\n        let id = CTR.fetch_add(1, Ordering::SeqCst);\n\n        HandlerId(id)\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/hooks.rs",
    "content": "use std::any::type_name;\nuse std::fmt;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse wasm_bindgen::prelude::*;\nuse yew::prelude::*;\n\nuse crate::utils::{BridgeIdState, OutputsAction, OutputsState};\nuse crate::worker::provider::WorkerProviderState;\nuse crate::worker::{Worker, WorkerBridge};\n\n/// Hook handle for the [`use_worker_bridge`] hook.\npub struct UseWorkerBridgeHandle<T>\nwhere\n    T: Worker,\n{\n    inner: Rc<WorkerBridge<T>>,\n    ctr: UseReducerDispatcher<BridgeIdState>,\n}\n\nimpl<T> UseWorkerBridgeHandle<T>\nwhere\n    T: Worker,\n{\n    /// Send an input to a worker agent.\n    pub fn send(&self, msg: T::Input) {\n        self.inner.send(msg);\n    }\n\n    /// Reset the bridge.\n    ///\n    /// Disconnect the old bridge and re-connects the agent with a new bridge.\n    pub fn reset(&self) {\n        self.ctr.dispatch(());\n    }\n}\n\nimpl<T> Clone for UseWorkerBridgeHandle<T>\nwhere\n    T: Worker,\n{\n    fn clone(&self) -> Self {\n        Self {\n            inner: self.inner.clone(),\n            ctr: self.ctr.clone(),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for UseWorkerBridgeHandle<T>\nwhere\n    T: Worker,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(type_name::<Self>())\n            .field(\"inner\", &self.inner)\n            .finish()\n    }\n}\n\nimpl<T> PartialEq for UseWorkerBridgeHandle<T>\nwhere\n    T: Worker,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.inner == rhs.inner\n    }\n}\n\n/// A hook to bridge to a [`Worker`].\n///\n/// This hooks will only bridge the worker once over the entire component lifecycle.\n///\n/// Takes a callback as the argument.\n///\n/// The callback will be updated on every render to make sure captured values (if any) are up to\n/// date.\n#[hook]\npub fn use_worker_bridge<T, F>(on_output: F) -> UseWorkerBridgeHandle<T>\nwhere\n    T: Worker + 'static,\n    F: Fn(T::Output) + 'static,\n{\n    let ctr = use_reducer(BridgeIdState::default);\n\n    let worker_state = use_context::<Rc<WorkerProviderState<T>>>()\n        .expect_throw(\"cannot find a provider for current agent.\");\n\n    let on_output = Rc::new(on_output);\n\n    let on_output_clone = on_output.clone();\n    let on_output_ref = use_mut_ref(move || on_output_clone);\n\n    // Refresh the callback on every render.\n    {\n        let mut on_output_ref = on_output_ref.borrow_mut();\n        *on_output_ref = on_output;\n    }\n\n    let bridge = use_memo((worker_state, ctr.inner), |(state, _ctr)| {\n        state.create_bridge(Callback::from(move |output| {\n            let on_output = on_output_ref.borrow().clone();\n            on_output(output);\n        }))\n    });\n\n    UseWorkerBridgeHandle {\n        inner: bridge,\n        ctr: ctr.dispatcher(),\n    }\n}\n\n/// Hook handle for the [`use_worker_subscription`] hook.\npub struct UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker,\n{\n    bridge: UseWorkerBridgeHandle<T>,\n    outputs: Vec<Rc<T::Output>>,\n    ctr: usize,\n}\n\nimpl<T> UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker,\n{\n    /// Send an input to a worker agent.\n    pub fn send(&self, msg: T::Input) {\n        self.bridge.send(msg);\n    }\n\n    /// Reset the subscription.\n    ///\n    /// This disconnects the old bridge and re-connects the agent with a new bridge.\n    /// Existing outputs stored in the subscription will also be cleared.\n    pub fn reset(&self) {\n        self.bridge.reset();\n    }\n}\n\nimpl<T> Clone for UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker,\n{\n    fn clone(&self) -> Self {\n        Self {\n            bridge: self.bridge.clone(),\n            outputs: self.outputs.clone(),\n            ctr: self.ctr,\n        }\n    }\n}\n\nimpl<T> fmt::Debug for UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker,\n    T::Output: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(type_name::<Self>())\n            .field(\"bridge\", &self.bridge)\n            .field(\"outputs\", &self.outputs)\n            .finish()\n    }\n}\n\nimpl<T> Deref for UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker,\n{\n    type Target = [Rc<T::Output>];\n\n    fn deref(&self) -> &[Rc<T::Output>] {\n        &self.outputs\n    }\n}\n\nimpl<T> PartialEq for UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.bridge == rhs.bridge && self.ctr == rhs.ctr\n    }\n}\n\n/// A hook to subscribe to the outputs of a [Worker] agent.\n///\n/// All outputs sent to current bridge will be collected into a slice.\n#[hook]\npub fn use_worker_subscription<T>() -> UseWorkerSubscriptionHandle<T>\nwhere\n    T: Worker + 'static,\n{\n    let outputs = use_reducer(OutputsState::default);\n\n    let bridge = {\n        let outputs = outputs.clone();\n        use_worker_bridge::<T, _>(move |output| {\n            outputs.dispatch(OutputsAction::Push(Rc::new(output)))\n        })\n    };\n\n    {\n        let outputs_dispatcher = outputs.dispatcher();\n        use_effect_with(bridge.clone(), move |_| {\n            outputs_dispatcher.dispatch(OutputsAction::Reset);\n\n            || {}\n        });\n    }\n\n    UseWorkerSubscriptionHandle {\n        bridge,\n        outputs: outputs.inner.clone(),\n        ctr: outputs.ctr,\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/lifecycle.rs",
    "content": "use wasm_bindgen::prelude::*;\n\nuse super::messages::ToWorker;\nuse super::native_worker::{DedicatedWorker, WorkerSelf};\nuse super::scope::{WorkerDestroyHandle, WorkerScope};\nuse super::traits::Worker;\nuse super::Shared;\n\npub(crate) struct WorkerState<W>\nwhere\n    W: Worker,\n{\n    worker: Option<(W, WorkerScope<W>)>,\n    to_destroy: bool,\n}\n\nimpl<W> WorkerState<W>\nwhere\n    W: Worker,\n{\n    pub fn new() -> Self {\n        WorkerState {\n            worker: None,\n            to_destroy: false,\n        }\n    }\n}\n\n/// Internal Worker lifecycle events\npub(crate) enum WorkerLifecycleEvent<W: Worker> {\n    /// Request to create the scope\n    Create(WorkerScope<W>),\n\n    /// Internal Worker message\n    Message(W::Message),\n\n    /// External Messages from bridges\n    Remote(ToWorker<W>),\n\n    /// Destroy the Worker\n    Destroy,\n}\n\npub(crate) struct WorkerRunnable<W: Worker> {\n    pub state: Shared<WorkerState<W>>,\n    pub event: WorkerLifecycleEvent<W>,\n}\n\nimpl<W> WorkerRunnable<W>\nwhere\n    W: Worker + 'static,\n{\n    pub fn run(self) {\n        let mut state = self.state.borrow_mut();\n\n        // We should block all event other than message after a worker is destroyed.\n        match self.event {\n            WorkerLifecycleEvent::Create(scope) => {\n                if state.to_destroy {\n                    return;\n                }\n                state.worker = Some((W::create(&scope), scope));\n            }\n            WorkerLifecycleEvent::Message(msg) => {\n                if let Some((worker, scope)) = state.worker.as_mut() {\n                    worker.update(scope, msg);\n                }\n            }\n            WorkerLifecycleEvent::Remote(ToWorker::Connected(id)) => {\n                if state.to_destroy {\n                    return;\n                }\n\n                let (worker, scope) = state\n                    .worker\n                    .as_mut()\n                    .expect_throw(\"worker was not created to process connected messages\");\n\n                worker.connected(scope, id);\n            }\n            WorkerLifecycleEvent::Remote(ToWorker::ProcessInput(id, inp)) => {\n                if state.to_destroy {\n                    return;\n                }\n\n                let (worker, scope) = state\n                    .worker\n                    .as_mut()\n                    .expect_throw(\"worker was not created to process inputs\");\n\n                worker.received(scope, inp, id);\n            }\n            WorkerLifecycleEvent::Remote(ToWorker::Disconnected(id)) => {\n                if state.to_destroy {\n                    return;\n                }\n\n                let (worker, scope) = state\n                    .worker\n                    .as_mut()\n                    .expect_throw(\"worker was not created to process disconnected messages\");\n\n                worker.disconnected(scope, id);\n            }\n            WorkerLifecycleEvent::Remote(ToWorker::Destroy) => {\n                if state.to_destroy {\n                    return;\n                }\n\n                state.to_destroy = true;\n\n                let (worker, scope) = state\n                    .worker\n                    .as_mut()\n                    .expect_throw(\"trying to destroy not existent worker\");\n\n                let destruct = WorkerDestroyHandle::new(scope.clone());\n\n                worker.destroy(scope, destruct);\n            }\n\n            WorkerLifecycleEvent::Destroy => {\n                state\n                    .worker\n                    .take()\n                    .expect_throw(\"worker is not initialised or already destroyed\");\n\n                DedicatedWorker::worker_self().close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/messages.rs",
    "content": "use serde::{Deserialize, Serialize};\n\nuse super::handler_id::HandlerId;\nuse super::traits::Worker;\n\n/// Serializable messages to worker\n#[derive(Serialize, Deserialize, Debug)]\npub(crate) enum ToWorker<W>\nwhere\n    W: Worker,\n{\n    /// Client is connected\n    Connected(HandlerId),\n    /// Incoming message to Worker\n    ProcessInput(HandlerId, W::Input),\n    /// Client is disconnected\n    Disconnected(HandlerId),\n    /// Worker should be terminated\n    Destroy,\n}\n\n/// Serializable messages sent by worker to consumer\n#[derive(Serialize, Deserialize, Debug)]\npub(crate) enum FromWorker<W>\nwhere\n    W: Worker,\n{\n    /// Worker sends this message when `wasm` bundle has loaded.\n    WorkerLoaded,\n    /// Outgoing message to consumer\n    ProcessOutput(HandlerId, W::Output),\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/mod.rs",
    "content": "//! This module contains the worker agent implementation.\n//!\n//! This is a low-level implementation that uses an actor model.\n//!\n//! # Example\n//!\n//! ```\n//! # mod example {\n//! use serde::{Deserialize, Serialize};\n//! use yew::prelude::*;\n//! use yew_agent::worker::{use_worker_bridge, UseWorkerBridgeHandle};\n//!\n//! // This would usually live in the same file as your worker\n//! #[derive(Serialize, Deserialize)]\n//! pub enum WorkerResponseType {\n//!     IncrementCounter,\n//! }\n//! # mod my_worker_mod {\n//! #   use yew_agent::worker::{HandlerId, WorkerScope};\n//! #   use super::WorkerResponseType;\n//! #   pub struct MyWorker {}\n//! #\n//! #   impl yew_agent::worker::Worker for MyWorker {\n//! #       type Input = ();\n//! #       type Output = WorkerResponseType;\n//! #       type Message = ();\n//! #\n//! #       fn create(scope: &WorkerScope<Self>) -> Self {\n//! #           MyWorker {}\n//! #       }\n//! #\n//! #       fn update(&mut self, scope: &WorkerScope<Self>, _msg: Self::Message) {\n//! #           // do nothing\n//! #       }\n//! #\n//! #       fn received(&mut self, scope: &WorkerScope<Self>, _msg: Self::Input, id: HandlerId) {\n//! #           scope.respond(id, WorkerResponseType::IncrementCounter);\n//! #       }\n//! #   }\n//! # }\n//! use my_worker_mod::MyWorker; // note that <MyWorker as yew_agent::Worker>::Output == WorkerResponseType\n//! #[component(UseWorkerBridge)]\n//! fn bridge() -> Html {\n//!     let counter = use_state(|| 0);\n//!\n//!     // a scoped block to clone the state in\n//!     {\n//!         let counter = counter.clone();\n//!         // response will be of type MyWorker::Output, i.e. WorkerResponseType\n//!         let bridge: UseWorkerBridgeHandle<MyWorker> = use_worker_bridge(move |response| match response {\n//!             WorkerResponseType::IncrementCounter => {\n//!                 counter.set(*counter + 1);\n//!             }\n//!         });\n//!     }\n//!\n//!     html! {\n//!         <div>\n//!             {*counter}\n//!         </div>\n//!     }\n//! }\n//! # }\n//! ```\n\nmod bridge;\nmod handler_id;\nmod hooks;\nmod lifecycle;\nmod messages;\nmod native_worker;\nmod provider;\nmod registrar;\nmod scope;\nmod spawner;\nmod traits;\n\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\npub use bridge::WorkerBridge;\npub use handler_id::HandlerId;\npub use hooks::{\n    use_worker_bridge, use_worker_subscription, UseWorkerBridgeHandle, UseWorkerSubscriptionHandle,\n};\npub(crate) use provider::WorkerProviderState;\npub use provider::{WorkerProvider, WorkerProviderProps};\npub use registrar::WorkerRegistrar;\npub use scope::{WorkerDestroyHandle, WorkerScope};\npub use spawner::WorkerSpawner;\npub use traits::Worker;\n\n/// Alias for `Rc<RefCell<T>>`\ntype Shared<T> = Rc<RefCell<T>>;\n\n/// Alias for `Rc<dyn Fn(IN)>`\ntype Callback<IN> = Rc<dyn Fn(IN)>;\n"
  },
  {
    "path": "packages/yew-agent/src/worker/native_worker.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse wasm_bindgen::closure::Closure;\nuse wasm_bindgen::prelude::*;\nuse wasm_bindgen::{JsCast, JsValue};\npub(crate) use web_sys::Worker as DedicatedWorker;\nuse web_sys::{DedicatedWorkerGlobalScope, MessageEvent};\n\nuse crate::codec::Codec;\n\npub(crate) trait WorkerSelf {\n    type GlobalScope;\n\n    fn worker_self() -> Self::GlobalScope;\n}\n\nimpl WorkerSelf for DedicatedWorker {\n    type GlobalScope = DedicatedWorkerGlobalScope;\n\n    fn worker_self() -> Self::GlobalScope {\n        JsValue::from(js_sys::global()).into()\n    }\n}\n\npub(crate) trait NativeWorkerExt {\n    fn set_on_packed_message<T, CODEC, F>(&self, handler: F)\n    where\n        T: Serialize + for<'de> Deserialize<'de>,\n        CODEC: Codec,\n        F: 'static + Fn(T);\n\n    fn post_packed_message<T, CODEC>(&self, data: T)\n    where\n        T: Serialize + for<'de> Deserialize<'de>,\n        CODEC: Codec;\n}\n\nmacro_rules! worker_ext_impl {\n    ($($type:path),+) => {$(\n        impl NativeWorkerExt for $type {\n            fn set_on_packed_message<T, CODEC, F>(&self, handler: F)\n            where\n                T: Serialize + for<'de> Deserialize<'de>,\n                CODEC: Codec,\n                F: 'static + Fn(T)\n            {\n                let handler = move |message: MessageEvent| {\n                    let msg = CODEC::decode(message.data());\n                    handler(msg);\n                };\n                let closure = Closure::wrap(Box::new(handler) as Box<dyn Fn(MessageEvent)>).into_js_value();\n                self.set_onmessage(Some(closure.as_ref().unchecked_ref()));\n            }\n\n            fn post_packed_message<T, CODEC>(&self, data: T)\n            where\n                T: Serialize + for<'de> Deserialize<'de>,\n                CODEC: Codec\n            {\n                self.post_message(&CODEC::encode(data))\n                    .expect_throw(\"failed to post message\");\n            }\n        }\n    )+};\n}\n\nworker_ext_impl! {\n    DedicatedWorker, DedicatedWorkerGlobalScope\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/provider.rs",
    "content": "use std::any::type_name;\nuse std::cell::RefCell;\nuse std::fmt;\nuse std::rc::Rc;\n\nuse serde::{Deserialize, Serialize};\nuse yew::prelude::*;\n\nuse super::{Worker, WorkerBridge};\nuse crate::reach::Reach;\nuse crate::utils::get_next_id;\nuse crate::{Bincode, Codec, Spawnable};\n\n/// Properties for [WorkerProvider].\n#[derive(Debug, Properties, PartialEq, Clone)]\npub struct WorkerProviderProps {\n    /// The path to an agent.\n    pub path: AttrValue,\n\n    /// The reachability of an agent.\n    ///\n    /// Default: [`Public`](Reach::Public).\n    #[prop_or(Reach::Public)]\n    pub reach: Reach,\n\n    /// Whether the agent should be created\n    /// with type `Module`.\n    #[prop_or(false)]\n    pub module: bool,\n\n    /// Lazily spawn the agent.\n    ///\n    /// The agent will be spawned when the first time a hook requests a bridge.\n    ///\n    /// Does not affect private agents.\n    ///\n    /// Default: `true`\n    #[prop_or(true)]\n    pub lazy: bool,\n\n    /// Children of the provider.\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub(crate) struct WorkerProviderState<W>\nwhere\n    W: Worker,\n{\n    id: usize,\n    spawn_bridge_fn: Rc<dyn Fn() -> WorkerBridge<W>>,\n    reach: Reach,\n    held_bridge: RefCell<Option<Rc<WorkerBridge<W>>>>,\n}\n\nimpl<W> fmt::Debug for WorkerProviderState<W>\nwhere\n    W: Worker,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(type_name::<Self>())\n    }\n}\n\nimpl<W> WorkerProviderState<W>\nwhere\n    W: Worker,\n    W::Output: 'static,\n{\n    fn get_held_bridge(&self) -> Rc<WorkerBridge<W>> {\n        let mut held_bridge = self.held_bridge.borrow_mut();\n\n        match held_bridge.as_mut() {\n            Some(m) => m.clone(),\n            None => {\n                let bridge = Rc::new((self.spawn_bridge_fn)());\n                *held_bridge = Some(bridge.clone());\n                bridge\n            }\n        }\n    }\n\n    /// Creates a bridge, uses \"fork\" for public agents.\n    pub fn create_bridge(&self, cb: Callback<W::Output>) -> WorkerBridge<W> {\n        match self.reach {\n            Reach::Public => {\n                let held_bridge = self.get_held_bridge();\n                held_bridge.fork(Some(move |m| cb.emit(m)))\n            }\n            Reach::Private => (self.spawn_bridge_fn)(),\n        }\n    }\n}\n\nimpl<W> PartialEq for WorkerProviderState<W>\nwhere\n    W: Worker,\n{\n    fn eq(&self, rhs: &Self) -> bool {\n        self.id == rhs.id\n    }\n}\n\n/// The Worker Agent Provider.\n///\n/// This component provides its children access to a worker agent.\n#[component]\npub fn WorkerProvider<W, C = Bincode>(props: &WorkerProviderProps) -> Html\nwhere\n    W: Worker + 'static,\n    W::Input: Serialize + for<'de> Deserialize<'de> + 'static,\n    W::Output: Serialize + for<'de> Deserialize<'de> + 'static,\n    C: Codec + 'static,\n{\n    let WorkerProviderProps {\n        children,\n        path,\n        lazy,\n        module,\n        reach,\n    } = props.clone();\n\n    // Creates a spawning function so Codec is can be erased from contexts.\n    let spawn_bridge_fn: Rc<dyn Fn() -> WorkerBridge<W>> = {\n        let path = path.clone();\n        Rc::new(move || W::spawner().as_module(module).encoding::<C>().spawn(&path))\n    };\n\n    let state = {\n        use_memo((path, lazy, reach), move |(_path, lazy, reach)| {\n            let state = WorkerProviderState::<W> {\n                id: get_next_id(),\n                spawn_bridge_fn,\n                reach: *reach,\n                held_bridge: Default::default(),\n            };\n\n            if *reach == Reach::Public && !*lazy {\n                state.get_held_bridge();\n            }\n            state\n        })\n    };\n\n    html! {\n        <ContextProvider<Rc<WorkerProviderState<W>>> context={state.clone()}>\n            {children}\n        </ContextProvider<Rc<WorkerProviderState<W>>>>\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/registrar.rs",
    "content": "use std::fmt;\nuse std::marker::PhantomData;\n\nuse serde::de::Deserialize;\nuse serde::ser::Serialize;\n\nuse super::lifecycle::WorkerLifecycleEvent;\nuse super::messages::{FromWorker, ToWorker};\nuse super::native_worker::{DedicatedWorker, NativeWorkerExt, WorkerSelf};\nuse super::scope::WorkerScope;\nuse super::traits::Worker;\nuse crate::codec::{Bincode, Codec};\n\n/// A Worker Registrar.\npub struct WorkerRegistrar<W, CODEC = Bincode>\nwhere\n    W: Worker,\n    CODEC: Codec,\n{\n    _marker: PhantomData<(W, CODEC)>,\n}\n\nimpl<W: Worker> fmt::Debug for WorkerRegistrar<W> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"WorkerRegistrar<_>\")\n    }\n}\n\nimpl<W, CODEC> WorkerRegistrar<W, CODEC>\nwhere\n    W: Worker + 'static,\n    CODEC: Codec,\n{\n    pub(crate) fn new() -> Self {\n        Self {\n            _marker: PhantomData,\n        }\n    }\n\n    /// Sets a new message encoding.\n    pub fn encoding<C>(&self) -> WorkerRegistrar<W, C>\n    where\n        C: Codec,\n    {\n        WorkerRegistrar::new()\n    }\n\n    /// Executes an worker in the current environment.\n    pub fn register(&self)\n    where\n        CODEC: Codec,\n        W::Input: Serialize + for<'de> Deserialize<'de>,\n        W::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        let scope = WorkerScope::<W>::new::<CODEC>();\n        let upd = WorkerLifecycleEvent::Create(scope.clone());\n        scope.send(upd);\n        let handler = move |msg: ToWorker<W>| {\n            let upd = WorkerLifecycleEvent::Remote(msg);\n            scope.send(upd);\n        };\n        let loaded: FromWorker<W> = FromWorker::WorkerLoaded;\n        let worker = DedicatedWorker::worker_self();\n        worker.set_on_packed_message::<_, CODEC, _>(handler);\n        worker.post_packed_message::<_, CODEC>(loaded);\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/scope.rs",
    "content": "use std::cell::RefCell;\nuse std::fmt;\nuse std::future::Future;\nuse std::rc::Rc;\n\nuse serde::de::Deserialize;\nuse serde::ser::Serialize;\nuse wasm_bindgen_futures::spawn_local;\n\nuse super::handler_id::HandlerId;\nuse super::lifecycle::{WorkerLifecycleEvent, WorkerRunnable, WorkerState};\nuse super::messages::FromWorker;\nuse super::native_worker::{DedicatedWorker, NativeWorkerExt, WorkerSelf};\nuse super::traits::Worker;\nuse super::Shared;\nuse crate::codec::Codec;\n\n/// A handle that closes the worker when it is dropped.\npub struct WorkerDestroyHandle<W>\nwhere\n    W: Worker + 'static,\n{\n    scope: WorkerScope<W>,\n}\n\nimpl<W: Worker> fmt::Debug for WorkerDestroyHandle<W> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"WorkerDestroyHandle<_>\")\n    }\n}\n\nimpl<W> WorkerDestroyHandle<W>\nwhere\n    W: Worker,\n{\n    pub(crate) fn new(scope: WorkerScope<W>) -> Self {\n        Self { scope }\n    }\n}\n\nimpl<W> Drop for WorkerDestroyHandle<W>\nwhere\n    W: Worker,\n{\n    fn drop(&mut self) {\n        self.scope.send(WorkerLifecycleEvent::Destroy);\n    }\n}\n\n/// This struct holds a reference to a component and to a global scheduler.\npub struct WorkerScope<W: Worker> {\n    state: Shared<WorkerState<W>>,\n    post_msg: Rc<dyn Fn(FromWorker<W>)>,\n}\n\nimpl<W: Worker> fmt::Debug for WorkerScope<W> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"WorkerScope<_>\")\n    }\n}\n\nimpl<W: Worker> Clone for WorkerScope<W> {\n    fn clone(&self) -> Self {\n        WorkerScope {\n            state: self.state.clone(),\n            post_msg: self.post_msg.clone(),\n        }\n    }\n}\n\nimpl<W> WorkerScope<W>\nwhere\n    W: Worker + 'static,\n{\n    /// Create worker scope\n    pub(crate) fn new<CODEC>() -> Self\n    where\n        CODEC: Codec,\n        W::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        let post_msg = move |msg: FromWorker<W>| {\n            DedicatedWorker::worker_self().post_packed_message::<_, CODEC>(msg)\n        };\n\n        let state = Rc::new(RefCell::new(WorkerState::new()));\n        WorkerScope {\n            post_msg: Rc::new(post_msg),\n            state,\n        }\n    }\n\n    /// Schedule message for sending to worker\n    pub(crate) fn send(&self, event: WorkerLifecycleEvent<W>) {\n        let state = self.state.clone();\n\n        // We can implement a custom scheduler,\n        // but it's easier to borrow the one from wasm-bindgen-futures.\n        spawn_local(async move {\n            WorkerRunnable { state, event }.run();\n        });\n    }\n\n    /// Send response to a worker bridge.\n    pub fn respond(&self, id: HandlerId, output: W::Output) {\n        let msg = FromWorker::<W>::ProcessOutput(id, output);\n        (self.post_msg)(msg);\n    }\n\n    /// Send a message to the worker\n    pub fn send_message<T>(&self, msg: T)\n    where\n        T: Into<W::Message>,\n    {\n        self.send(WorkerLifecycleEvent::Message(msg.into()));\n    }\n\n    /// Create a callback which will send a message to the worker when invoked.\n    pub fn callback<F, IN, M>(&self, function: F) -> Rc<dyn Fn(IN)>\n    where\n        M: Into<W::Message>,\n        F: Fn(IN) -> M + 'static,\n    {\n        let scope = self.clone();\n        let closure = move |input| {\n            let output = function(input).into();\n            scope.send(WorkerLifecycleEvent::Message(output));\n        };\n        Rc::new(closure)\n    }\n\n    /// This method creates a callback which returns a Future which\n    /// returns a message to be sent back to the worker\n    ///\n    /// # Panics\n    /// If the future panics, then the promise will not resolve, and\n    /// will leak.\n    pub fn callback_future<FN, FU, IN, M>(&self, function: FN) -> Rc<dyn Fn(IN)>\n    where\n        M: Into<W::Message>,\n        FU: Future<Output = M> + 'static,\n        FN: Fn(IN) -> FU + 'static,\n    {\n        let scope = self.clone();\n\n        let closure = move |input: IN| {\n            let future: FU = function(input);\n            scope.send_future(future);\n        };\n\n        Rc::new(closure)\n    }\n\n    /// This method processes a Future that returns a message and sends it back to the worker.\n    ///\n    /// # Panics\n    /// If the future panics, then the promise will not resolve, and will leak.\n    pub fn send_future<F, M>(&self, future: F)\n    where\n        M: Into<W::Message>,\n        F: Future<Output = M> + 'static,\n    {\n        let scope = self.clone();\n        let js_future = async move {\n            let message: W::Message = future.await.into();\n            let cb = scope.callback(|m: W::Message| m);\n            (*cb)(message);\n        };\n        wasm_bindgen_futures::spawn_local(js_future);\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/spawner.rs",
    "content": "use std::cell::RefCell;\nuse std::collections::HashMap;\nuse std::fmt;\nuse std::marker::PhantomData;\nuse std::rc::{Rc, Weak};\n\nuse js_sys::Array;\nuse serde::de::Deserialize;\nuse serde::ser::Serialize;\nuse web_sys::{Blob, BlobPropertyBag, Url, WorkerOptions, WorkerType};\n\nuse super::bridge::{CallbackMap, WorkerBridge};\nuse super::handler_id::HandlerId;\nuse super::messages::FromWorker;\nuse super::native_worker::{DedicatedWorker, NativeWorkerExt};\nuse super::traits::Worker;\nuse super::{Callback, Shared};\nuse crate::codec::{Bincode, Codec};\nuse crate::utils::window;\n\n/// A spawner to create workers.\n#[derive(Clone)]\npub struct WorkerSpawner<W, CODEC = Bincode>\nwhere\n    W: Worker,\n    CODEC: Codec,\n{\n    _marker: PhantomData<(W, CODEC)>,\n    callback: Option<Callback<W::Output>>,\n    with_loader: bool,\n    as_module: bool,\n}\n\nimpl<W, CODEC> fmt::Debug for WorkerSpawner<W, CODEC>\nwhere\n    W: Worker,\n    CODEC: Codec,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"WorkerScope<_>\")\n    }\n}\n\nimpl<W, CODEC> Default for WorkerSpawner<W, CODEC>\nwhere\n    W: Worker + 'static,\n    CODEC: Codec,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<W, CODEC> WorkerSpawner<W, CODEC>\nwhere\n    W: Worker + 'static,\n    CODEC: Codec,\n{\n    /// Creates a [WorkerSpawner].\n    pub const fn new() -> Self {\n        Self {\n            _marker: PhantomData,\n            callback: None,\n            with_loader: false,\n            as_module: false,\n        }\n    }\n\n    /// Sets a new message encoding.\n    pub fn encoding<C>(&mut self) -> WorkerSpawner<W, C>\n    where\n        C: Codec,\n    {\n        WorkerSpawner {\n            _marker: PhantomData,\n            callback: self.callback.clone(),\n            with_loader: self.with_loader,\n            as_module: self.as_module,\n        }\n    }\n\n    /// Sets a callback.\n    pub fn callback<F>(&mut self, cb: F) -> &mut Self\n    where\n        F: 'static + Fn(W::Output),\n    {\n        self.callback = Some(Rc::new(cb));\n\n        self\n    }\n\n    /// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a\n    /// `path` to a loader shim script (e.g. when using Trunk, created by using\n    /// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types)\n    /// asset type) and one does not need to be generated. `false` by default.\n    pub fn with_loader(&mut self, with_loader: bool) -> &mut Self {\n        self.with_loader = with_loader;\n\n        self\n    }\n\n    /// Determines whether the worker will be spawned with\n    /// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)\n    /// set to `module`. `true` by default.\n    ///\n    /// This option should be un-set if the worker was created with the\n    /// `--target no-modules` flag of `wasm-bindgen`. If using Trunk, see the\n    /// [`data-bindgen-target`](https://trunkrs.dev/assets/#link-asset-types)\n    /// asset type.\n    pub fn as_module(&mut self, as_module: bool) -> &mut Self {\n        self.as_module = as_module;\n\n        self\n    }\n\n    /// Spawns a Worker.\n    pub fn spawn(&self, path: &str) -> WorkerBridge<W>\n    where\n        W::Input: Serialize + for<'de> Deserialize<'de>,\n        W::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        let worker = self.create_worker(path).expect(\"failed to spawn worker\");\n\n        self.spawn_inner(worker)\n    }\n\n    fn create_worker(&self, path: &str) -> Option<DedicatedWorker> {\n        let path = if self.with_loader {\n            std::borrow::Cow::Borrowed(path)\n        } else {\n            let js_shim_url = Url::new_with_base(\n                path,\n                &window().location().href().expect(\"failed to read href.\"),\n            )\n            .expect(\"failed to create url for javascript entrypoint\")\n            .to_string();\n\n            let wasm_url = js_shim_url.replace(\".js\", \"_bg.wasm\");\n\n            let array = Array::new();\n            let shim = if self.as_module {\n                format!(r#\"import init from '{js_shim_url}';await init();\"#)\n            } else {\n                format!(r#\"importScripts(\"{js_shim_url}\");wasm_bindgen(\"{wasm_url}\");\"#)\n            };\n            array.push(&shim.into());\n            let blob_property = BlobPropertyBag::new();\n            blob_property.set_type(\"application/javascript\");\n            let blob = Blob::new_with_str_sequence_and_options(&array, &blob_property).unwrap();\n            let url = Url::create_object_url_with_blob(&blob).unwrap();\n            std::borrow::Cow::Owned(url)\n        };\n        let path = path.as_ref();\n\n        if self.as_module {\n            let options = WorkerOptions::new();\n            options.set_type(WorkerType::Module);\n            DedicatedWorker::new_with_options(path, &options).ok()\n        } else {\n            DedicatedWorker::new(path).ok()\n        }\n    }\n\n    fn spawn_inner(&self, worker: DedicatedWorker) -> WorkerBridge<W>\n    where\n        W::Input: Serialize + for<'de> Deserialize<'de>,\n        W::Output: Serialize + for<'de> Deserialize<'de>,\n    {\n        let pending_queue = Rc::new(RefCell::new(Some(Vec::new())));\n        let handler_id = HandlerId::new();\n        let mut callbacks = HashMap::new();\n\n        if let Some(m) = self.callback.as_ref().map(Rc::downgrade) {\n            callbacks.insert(handler_id, m);\n        }\n\n        let callbacks: Shared<CallbackMap<W>> = Rc::new(RefCell::new(callbacks));\n\n        let handler = {\n            let pending_queue = pending_queue.clone();\n            let callbacks = callbacks.clone();\n\n            let worker = worker.clone();\n\n            move |msg: FromWorker<W>| match msg {\n                FromWorker::WorkerLoaded => {\n                    if let Some(pending_queue) = pending_queue.borrow_mut().take() {\n                        for to_worker in pending_queue.into_iter() {\n                            worker.post_packed_message::<_, CODEC>(to_worker);\n                        }\n                    }\n                }\n                FromWorker::ProcessOutput(id, output) => {\n                    let mut callbacks = callbacks.borrow_mut();\n\n                    if let Some(m) = callbacks.get(&id) {\n                        if let Some(m) = Weak::upgrade(m) {\n                            m(output);\n                        } else {\n                            callbacks.remove(&id);\n                        }\n                    }\n                }\n            }\n        };\n\n        worker.set_on_packed_message::<_, CODEC, _>(handler);\n\n        WorkerBridge::<W>::new::<CODEC>(\n            handler_id,\n            worker,\n            pending_queue,\n            callbacks,\n            self.callback.clone(),\n        )\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent/src/worker/traits.rs",
    "content": "use super::handler_id::HandlerId;\nuse super::registrar::WorkerRegistrar;\nuse super::scope::{WorkerDestroyHandle, WorkerScope};\nuse super::spawner::WorkerSpawner;\nuse crate::traits::{Registrable, Spawnable};\n\n/// Declares the behaviour of a worker.\npub trait Worker: Sized {\n    /// Update message type.\n    type Message;\n    /// Incoming message type.\n    type Input;\n    /// Outgoing message type.\n    type Output;\n\n    /// Creates an instance of a worker.\n    fn create(scope: &WorkerScope<Self>) -> Self;\n\n    /// Receives an update.\n    ///\n    /// This method is called when the worker send messages to itself via\n    /// [`WorkerScope::send_message`].\n    fn update(&mut self, scope: &WorkerScope<Self>, msg: Self::Message);\n\n    /// New bridge created.\n    ///\n    /// When a new bridge is created by [`WorkerSpawner::spawn`](crate::WorkerSpawner)\n    /// or [`WorkerBridge::fork`](crate::WorkerBridge::fork),\n    /// the worker will be notified the [`HandlerId`] of the created bridge via this method.\n    fn connected(&mut self, scope: &WorkerScope<Self>, id: HandlerId) {\n        let _scope = scope;\n        let _id = id;\n    }\n\n    /// Receives an input from a connected bridge.\n    ///\n    /// When a bridge sends an input via [`WorkerBridge::send`](crate::WorkerBridge::send), the\n    /// worker will receive the input via this method.\n    fn received(&mut self, scope: &WorkerScope<Self>, msg: Self::Input, id: HandlerId);\n\n    /// Existing bridge destroyed.\n    ///\n    /// When a bridge is dropped, the worker will be notified with this method.\n    fn disconnected(&mut self, scope: &WorkerScope<Self>, id: HandlerId) {\n        let _scope = scope;\n        let _id = id;\n    }\n\n    /// Destroys the current worker.\n    ///\n    /// When all bridges are dropped, the method will be invoked.\n    ///\n    /// This method is provided a destroy handle where when it is dropped, the worker is closed.\n    /// If the worker is closed immediately, then it can ignore the destroy handle.\n    /// Otherwise hold the destroy handle until the clean up task is finished.\n    ///\n    /// # Note\n    ///\n    /// This method will only be called after all bridges are disconnected.\n    /// Attempting to send messages after this method is called will have no effect.\n    fn destroy(&mut self, scope: &WorkerScope<Self>, destruct: WorkerDestroyHandle<Self>) {\n        let _scope = scope;\n        let _destruct = destruct;\n    }\n}\n\nimpl<W> Spawnable for W\nwhere\n    W: Worker + 'static,\n{\n    type Spawner = WorkerSpawner<Self>;\n\n    fn spawner() -> WorkerSpawner<Self> {\n        WorkerSpawner::new()\n    }\n}\n\nimpl<W> Registrable for W\nwhere\n    W: Worker + 'static,\n{\n    type Registrar = WorkerRegistrar<Self>;\n\n    fn registrar() -> WorkerRegistrar<Self> {\n        WorkerRegistrar::new()\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent-macro/Cargo.toml",
    "content": "[package]\nname = \"yew-agent-macro\"\nversion = \"0.4.0\"\nedition = \"2021\"\nrust-version = \"1.84.0\"\nauthors = [\"Kaede Hoshikawa <futursolo@icloud.com>\"]\nrepository = \"https://github.com/yewstack/yew\"\nhomepage = \"https://yew.rs\"\ndocumentation = \"https://docs.rs/yew/\"\nreadme = \"../../README.md\"\ndescription = \"Macro Support for Yew Agents\"\nlicense = \"MIT OR Apache-2.0\"\n\n[lib]\nproc-macro = true\n\n[dependencies]\nproc-macro2.workspace = true\nquote.workspace = true\nsyn = { workspace = true, features = [\"full\", \"extra-traits\"] }\n\n[dev-dependencies]\nrustversion.workspace = true\ntrybuild = { workspace = true }\nyew-agent = { path = \"../yew-agent\" }\n"
  },
  {
    "path": "packages/yew-agent-macro/release.toml",
    "content": "tag = false\n"
  },
  {
    "path": "packages/yew-agent-macro/src/agent_fn.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse quote::ToTokens;\nuse syn::parse::{Parse, ParseStream};\nuse syn::punctuated::Punctuated;\nuse syn::token::Comma;\nuse syn::{Attribute, FnArg, Generics, Ident, Item, ItemFn, Signature, Type, Visibility};\n\npub trait AgentFnType {\n    type RecvType;\n    type OutputType;\n\n    fn attr_name() -> &'static str;\n    fn agent_type_name() -> &'static str;\n    fn parse_recv_type(sig: &Signature) -> syn::Result<Self::RecvType>;\n    fn parse_output_type(sig: &Signature) -> syn::Result<Self::OutputType>;\n\n    fn extract_fn_arg_type(arg: &FnArg) -> syn::Result<Type> {\n        let ty = match arg {\n            FnArg::Typed(arg) => arg.ty.clone(),\n\n            FnArg::Receiver(_) => {\n                return Err(syn::Error::new_spanned(\n                    arg,\n                    format!(\"{} agents can't accept a receiver\", Self::agent_type_name()),\n                ));\n            }\n        };\n\n        Ok(*ty)\n    }\n\n    fn assert_no_left_argument<I, T>(rest_inputs: I, expected_len: usize) -> syn::Result<()>\n    where\n        I: ExactSizeIterator + IntoIterator<Item = T>,\n        T: ToTokens,\n    {\n        // Checking after param parsing may make it a little inefficient\n        // but that's a requirement for better error messages in case of receivers\n        // `>0` because first one is already consumed.\n        if rest_inputs.len() > 0 {\n            let params: TokenStream = rest_inputs\n                .into_iter()\n                .map(|it| it.to_token_stream())\n                .collect();\n            return Err(syn::Error::new_spanned(\n                params,\n                format!(\n                    \"{} agent can accept at most {} argument{}\",\n                    Self::agent_type_name(),\n                    expected_len,\n                    if expected_len > 1 { \"s\" } else { \"\" }\n                ),\n            ));\n        }\n\n        Ok(())\n    }\n}\n\n#[derive(Clone)]\npub struct AgentFn<F>\nwhere\n    F: AgentFnType + 'static,\n{\n    pub recv_type: F::RecvType,\n    pub output_type: F::OutputType,\n    pub generics: Generics,\n    pub vis: Visibility,\n    pub attrs: Vec<Attribute>,\n    pub name: Ident,\n    pub agent_name: Option<Ident>,\n    pub is_async: bool,\n\n    pub func: ItemFn,\n}\n\nimpl<F> Parse for AgentFn<F>\nwhere\n    F: AgentFnType + 'static,\n{\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let parsed: Item = input.parse()?;\n\n        let func = match parsed {\n            Item::Fn(m) => m,\n\n            item => {\n                return Err(syn::Error::new_spanned(\n                    item,\n                    format!(\n                        \"`{}` attribute can only be applied to functions\",\n                        F::attr_name()\n                    ),\n                ))\n            }\n        };\n\n        let ItemFn {\n            attrs, vis, sig, ..\n        } = func.clone();\n\n        if sig.generics.lifetimes().next().is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.generics,\n                format!(\n                    \"{} agents can't have generic lifetime parameters\",\n                    F::agent_type_name()\n                ),\n            ));\n        }\n\n        if sig.constness.is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.constness,\n                format!(\"const functions can't be {} agents\", F::agent_type_name()),\n            ));\n        }\n\n        if sig.abi.is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.abi,\n                format!(\"extern functions can't be {} agents\", F::agent_type_name()),\n            ));\n        }\n        let recv_type = F::parse_recv_type(&sig)?;\n        let output_type = F::parse_output_type(&sig)?;\n\n        let is_async = sig.asyncness.is_some();\n\n        Ok(Self {\n            recv_type,\n            output_type,\n            generics: sig.generics,\n            is_async,\n            vis,\n            attrs,\n            name: sig.ident,\n            agent_name: None,\n            func,\n        })\n    }\n}\n\nimpl<F> AgentFn<F>\nwhere\n    F: AgentFnType + 'static,\n{\n    /// Filters attributes that should be copied to agent definition.\n    pub fn filter_attrs_for_agent_struct(&self) -> Vec<Attribute> {\n        self.attrs\n            .iter()\n            .filter_map(|m| {\n                m.path()\n                    .get_ident()\n                    .and_then(|ident| match ident.to_string().as_str() {\n                        \"doc\" | \"allow\" => Some(m.clone()),\n                        _ => None,\n                    })\n            })\n            .collect()\n    }\n\n    /// Filters attributes that should be copied to the agent impl block.\n    pub fn filter_attrs_for_agent_impl(&self) -> Vec<Attribute> {\n        self.attrs\n            .iter()\n            .filter_map(|m| {\n                m.path()\n                    .get_ident()\n                    .and_then(|ident| match ident.to_string().as_str() {\n                        \"allow\" => Some(m.clone()),\n                        _ => None,\n                    })\n            })\n            .collect()\n    }\n\n    pub fn phantom_generics(&self) -> Punctuated<Ident, Comma> {\n        self.generics\n            .type_params()\n            .map(|ty_param| ty_param.ident.clone()) // create a new Punctuated sequence without any type bounds\n            .collect::<Punctuated<_, Comma>>()\n    }\n\n    pub fn merge_agent_name(&mut self, name: AgentName) -> syn::Result<()> {\n        if let Some(ref m) = name.agent_name {\n            if m == &self.name {\n                return Err(syn::Error::new_spanned(\n                    m,\n                    format!(\n                        \"the {} must not have the same name as the function\",\n                        F::agent_type_name()\n                    ),\n                ));\n            }\n        }\n\n        self.agent_name = name.agent_name;\n\n        Ok(())\n    }\n\n    pub fn inner_fn_ident(&self) -> Ident {\n        if self.agent_name.is_some() {\n            self.name.clone()\n        } else {\n            Ident::new(\"inner\", Span::mixed_site())\n        }\n    }\n\n    pub fn agent_name(&self) -> Ident {\n        self.agent_name.clone().unwrap_or_else(|| self.name.clone())\n    }\n\n    pub fn print_inner_fn(&self) -> ItemFn {\n        let mut func = self.func.clone();\n        func.sig.ident = self.inner_fn_ident();\n\n        func.vis = Visibility::Inherited;\n\n        func\n    }\n}\n\npub struct AgentName {\n    agent_name: Option<Ident>,\n}\n\nimpl Parse for AgentName {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        if input.is_empty() {\n            return Ok(Self { agent_name: None });\n        }\n\n        let agent_name = input.parse()?;\n\n        Ok(Self {\n            agent_name: Some(agent_name),\n        })\n    }\n}\n"
  },
  {
    "path": "packages/yew-agent-macro/src/lib.rs",
    "content": "use proc_macro::TokenStream;\nuse syn::parse_macro_input;\n\nmod agent_fn;\nmod oneshot;\nmod reactor;\n\nuse agent_fn::{AgentFn, AgentName};\nuse oneshot::{oneshot_impl, OneshotFn};\nuse reactor::{reactor_impl, ReactorFn};\n\n#[proc_macro_attribute]\npub fn reactor(attr: TokenStream, item: TokenStream) -> TokenStream {\n    let item = parse_macro_input!(item as AgentFn<ReactorFn>);\n    let attr = parse_macro_input!(attr as AgentName);\n\n    reactor_impl(attr, item)\n        .unwrap_or_else(|err| err.to_compile_error())\n        .into()\n}\n\n#[proc_macro_attribute]\npub fn oneshot(attr: TokenStream, item: TokenStream) -> TokenStream {\n    let item = parse_macro_input!(item as AgentFn<OneshotFn>);\n    let attr = parse_macro_input!(attr as AgentName);\n\n    oneshot_impl(attr, item)\n        .unwrap_or_else(|err| err.to_compile_error())\n        .into()\n}\n"
  },
  {
    "path": "packages/yew-agent-macro/src/oneshot.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse quote::quote;\nuse syn::{parse_quote, Ident, ReturnType, Signature, Type};\n\nuse crate::agent_fn::{AgentFn, AgentFnType, AgentName};\n\npub struct OneshotFn {}\n\nimpl AgentFnType for OneshotFn {\n    type OutputType = Type;\n    type RecvType = Type;\n\n    fn attr_name() -> &'static str {\n        \"oneshot\"\n    }\n\n    fn agent_type_name() -> &'static str {\n        \"oneshot\"\n    }\n\n    fn parse_recv_type(sig: &Signature) -> syn::Result<Self::RecvType> {\n        let mut inputs = sig.inputs.iter();\n        let arg = inputs\n            .next()\n            .ok_or_else(|| syn::Error::new_spanned(&sig.ident, \"expected 1 argument\"))?;\n\n        let ty = Self::extract_fn_arg_type(arg)?;\n\n        Self::assert_no_left_argument(inputs, 1)?;\n\n        Ok(ty)\n    }\n\n    fn parse_output_type(sig: &Signature) -> syn::Result<Self::OutputType> {\n        let ty = match &sig.output {\n            ReturnType::Default => {\n                parse_quote! { () }\n            }\n            ReturnType::Type(_, ty) => *ty.clone(),\n        };\n\n        Ok(ty)\n    }\n}\n\npub fn oneshot_impl(name: AgentName, mut agent_fn: AgentFn<OneshotFn>) -> syn::Result<TokenStream> {\n    agent_fn.merge_agent_name(name)?;\n\n    let struct_attrs = agent_fn.filter_attrs_for_agent_struct();\n    let oneshot_impl_attrs = agent_fn.filter_attrs_for_agent_impl();\n    let phantom_generics = agent_fn.phantom_generics();\n    let oneshot_name = agent_fn.agent_name();\n    let fn_name = agent_fn.inner_fn_ident();\n    let inner_fn = agent_fn.print_inner_fn();\n\n    let AgentFn {\n        recv_type: input_type,\n        generics,\n        output_type,\n        vis,\n        is_async,\n        ..\n    } = agent_fn;\n    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();\n    let fn_generics = ty_generics.as_turbofish();\n\n    let in_ident = Ident::new(\"_input\", Span::mixed_site());\n\n    let fn_call = if is_async {\n        quote! { #fn_name #fn_generics (#in_ident).await }\n    } else {\n        quote! { #fn_name #fn_generics (#in_ident) }\n    };\n    let crate_name = quote! { yew_agent };\n\n    let quoted = quote! {\n        #(#struct_attrs)*\n        #[allow(unused_parens)]\n        #vis struct #oneshot_name #generics #where_clause {\n            inner: ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #output_type>>>,\n            _marker: ::std::marker::PhantomData<(#phantom_generics)>,\n        }\n\n        // we cannot disable any lints here because it will be applied to the function body\n        // as well.\n        #(#oneshot_impl_attrs)*\n        impl #impl_generics ::#crate_name::oneshot::Oneshot for #oneshot_name #ty_generics #where_clause {\n            type Input = #input_type;\n\n            fn create(#in_ident: Self::Input) -> Self {\n                #inner_fn\n\n                Self {\n                    inner: ::std::boxed::Box::pin(\n                        async move {\n                            #fn_call\n                        }\n                    ),\n                    _marker: ::std::marker::PhantomData,\n                }\n            }\n        }\n\n        impl #impl_generics ::std::future::Future for #oneshot_name #ty_generics #where_clause {\n            type Output = #output_type;\n\n            fn poll(mut self: ::std::pin::Pin<&mut Self>, cx: &mut ::std::task::Context<'_>) -> ::std::task::Poll<Self::Output> {\n                ::std::future::Future::poll(::std::pin::Pin::new(&mut self.inner), cx)\n            }\n        }\n\n        impl #impl_generics ::#crate_name::Registrable for #oneshot_name #ty_generics #where_clause {\n            type Registrar = ::#crate_name::oneshot::OneshotRegistrar<Self>;\n\n            fn registrar() -> Self::Registrar {\n                ::#crate_name::oneshot::OneshotRegistrar::<Self>::new()\n            }\n        }\n\n        impl #impl_generics ::#crate_name::Spawnable for #oneshot_name #ty_generics #where_clause {\n            type Spawner = ::#crate_name::oneshot::OneshotSpawner<Self>;\n\n            fn spawner() -> Self::Spawner {\n                ::#crate_name::oneshot::OneshotSpawner::<Self>::new()\n            }\n        }\n    };\n\n    Ok(quoted)\n}\n"
  },
  {
    "path": "packages/yew-agent-macro/src/reactor.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse quote::quote;\nuse syn::{Ident, ReturnType, Signature, Type};\n\nuse crate::agent_fn::{AgentFn, AgentFnType, AgentName};\n\npub struct ReactorFn {}\n\nimpl AgentFnType for ReactorFn {\n    type OutputType = ();\n    type RecvType = Type;\n\n    fn attr_name() -> &'static str {\n        \"reactor\"\n    }\n\n    fn agent_type_name() -> &'static str {\n        \"reactor\"\n    }\n\n    fn parse_recv_type(sig: &Signature) -> syn::Result<Self::RecvType> {\n        let mut inputs = sig.inputs.iter();\n        let arg = inputs\n            .next()\n            .ok_or_else(|| syn::Error::new_spanned(&sig.ident, \"expected 1 argument\"))?;\n\n        let ty = Self::extract_fn_arg_type(arg)?;\n\n        Self::assert_no_left_argument(inputs, 1)?;\n\n        Ok(ty)\n    }\n\n    fn parse_output_type(sig: &Signature) -> syn::Result<Self::OutputType> {\n        match &sig.output {\n            ReturnType::Default => {}\n            ReturnType::Type(_, ty) => {\n                return Err(syn::Error::new_spanned(\n                    ty,\n                    \"reactor agents cannot return any value\",\n                ))\n            }\n        }\n\n        Ok(())\n    }\n}\n\npub fn reactor_impl(name: AgentName, mut agent_fn: AgentFn<ReactorFn>) -> syn::Result<TokenStream> {\n    agent_fn.merge_agent_name(name)?;\n\n    if !agent_fn.is_async {\n        return Err(syn::Error::new_spanned(\n            &agent_fn.name,\n            \"reactor agents must be asynchronous\",\n        ));\n    }\n\n    let struct_attrs = agent_fn.filter_attrs_for_agent_struct();\n    let reactor_impl_attrs = agent_fn.filter_attrs_for_agent_impl();\n    let phantom_generics = agent_fn.phantom_generics();\n    let reactor_name = agent_fn.agent_name();\n    let fn_name = agent_fn.inner_fn_ident();\n    let inner_fn = agent_fn.print_inner_fn();\n\n    let AgentFn {\n        recv_type,\n        generics,\n        vis,\n        ..\n    } = agent_fn;\n\n    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();\n    let fn_generics = ty_generics.as_turbofish();\n\n    let scope_ident = Ident::new(\"_scope\", Span::mixed_site());\n\n    let fn_call = quote! { #fn_name #fn_generics (#scope_ident).await };\n    let crate_name = quote! { yew_agent };\n\n    let quoted = quote! {\n        #(#struct_attrs)*\n        #[allow(unused_parens)]\n        #vis struct #reactor_name #generics #where_clause {\n            inner: ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ()>>>,\n            _marker: ::std::marker::PhantomData<(#phantom_generics)>,\n        }\n\n        // we cannot disable any lints here because it will be applied to the function body\n        // as well.\n        #(#reactor_impl_attrs)*\n        impl #impl_generics ::#crate_name::reactor::Reactor for #reactor_name #ty_generics #where_clause {\n            type Scope = #recv_type;\n\n            fn create(#scope_ident: Self::Scope) -> Self {\n                #inner_fn\n\n                Self {\n                    inner: ::std::boxed::Box::pin(\n                        async move {\n                            #fn_call\n                        }\n                    ),\n                    _marker: ::std::marker::PhantomData,\n                }\n            }\n        }\n\n        impl #impl_generics ::std::future::Future for #reactor_name #ty_generics #where_clause {\n            type Output = ();\n\n            fn poll(mut self: ::std::pin::Pin<&mut Self>, cx: &mut ::std::task::Context<'_>) -> ::std::task::Poll<Self::Output> {\n                ::std::future::Future::poll(::std::pin::Pin::new(&mut self.inner), cx)\n            }\n        }\n\n        impl #impl_generics ::#crate_name::Registrable for #reactor_name #ty_generics #where_clause {\n            type Registrar = ::#crate_name::reactor::ReactorRegistrar<Self>;\n\n            fn registrar() -> Self::Registrar {\n                ::#crate_name::reactor::ReactorRegistrar::<Self>::new()\n            }\n        }\n\n        impl #impl_generics ::#crate_name::Spawnable for #reactor_name #ty_generics #where_clause {\n            type Spawner = ::#crate_name::reactor::ReactorSpawner<Self>;\n\n            fn spawner() -> Self::Spawner {\n                ::#crate_name::reactor::ReactorSpawner::<Self>::new()\n            }\n        }\n    };\n\n    Ok(quoted)\n}\n"
  },
  {
    "path": "packages/yew-macro/Cargo.toml",
    "content": "[package]\nname = \"yew-macro\"\nversion = \"0.23.0\"\nedition = \"2021\"\nauthors = [\"Justin Starry <justin@yew.rs>\"]\nrepository = \"https://github.com/yewstack/yew\"\nhomepage = \"https://github.com/yewstack/yew\"\ndocumentation = \"https://docs.rs/yew-macro/\"\nlicense = \"MIT OR Apache-2.0\"\nkeywords = [\"web\", \"wasm\", \"frontend\", \"webasm\", \"webassembly\"]\ncategories = [\"gui\", \"web-programming\", \"wasm\"]\ndescription = \"A framework for making client-side single-page apps\"\nrust-version = \"1.84.0\"\n\n[lib]\nproc-macro = true\n\n[dependencies]\nproc-macro-error = \"1\"\nproc-macro2.workspace = true\nquote.workspace = true\nsyn = { workspace = true, features = [\"full\", \"extra-traits\", \"visit-mut\"] }\nprettyplease = \"0.2\"\nrustversion.workspace = true\n\n# testing\n[dev-dependencies]\ntrybuild = { workspace = true }\nyew = { path = \"../yew\" }\nimplicit-clone = { workspace = true }\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "packages/yew-macro/Makefile.toml",
    "content": "[tasks.test]\nclear = true\ntoolchain = \"1.84.0\"\ncommand = \"cargo\"\n# test target can be optionally specified like `cargo make test html_macro`,\nargs = [\"test\", \"${@}\"]\n\n[tasks.test-lint]\nclear = true\ntoolchain = \"nightly\"\ncommand = \"cargo\"\nargs = [\"test\", \"test_html_lints\", \"--features\", \"lints\"]\n\n[tasks.test-overwrite]\nextend = \"test\"\nenv = { TRYBUILD = \"overwrite\" }\n"
  },
  {
    "path": "packages/yew-macro/release.toml",
    "content": "tag = false\n"
  },
  {
    "path": "packages/yew-macro/src/classes/mod.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::parse::{Parse, ParseStream};\nuse syn::punctuated::Punctuated;\nuse syn::spanned::Spanned;\nuse syn::{Expr, ExprLit, Lit, LitStr, Token};\n\n/// List of HTML classes.\npub struct Classes(Punctuated<ClassExpr, Token![,]>);\n\nimpl Parse for Classes {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        input\n            .parse_terminated(ClassExpr::parse, Token![,])\n            .map(Self)\n    }\n}\n\nimpl ToTokens for Classes {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let n = self.0.len();\n        let push_classes = self.0.iter().map(|x| match x {\n            ClassExpr::Lit(class) => quote! {\n                unsafe { __yew_classes.unchecked_push(#class) };\n            },\n            ClassExpr::Expr(class) => quote_spanned! {class.span()=>\n                __yew_classes.push(#class);\n            },\n        });\n        tokens.extend(quote! {\n            {\n                let mut __yew_classes = ::yew::html::Classes::with_capacity(#n);\n                #(#push_classes)*\n                __yew_classes\n            }\n        });\n    }\n}\n\nenum ClassExpr {\n    Lit(LitStr),\n    Expr(Box<Expr>),\n}\n\nimpl Parse for ClassExpr {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        match input.parse()? {\n            Expr::Lit(ExprLit {\n                lit: Lit::Str(lit_str),\n                ..\n            }) => {\n                let value = lit_str.value();\n                let classes = value.split_whitespace().collect::<Vec<_>>();\n                if classes.len() > 1 {\n                    let fix = classes\n                        .into_iter()\n                        .map(|class| format!(\"\\\"{class}\\\"\"))\n                        .collect::<Vec<_>>()\n                        .join(\", \");\n                    let msg = format!(\n                        \"string literals must not contain more than one class (hint: use `{fix}`)\"\n                    );\n\n                    Err(syn::Error::new(lit_str.span(), msg))\n                } else {\n                    Ok(Self::Lit(lit_str))\n                }\n            }\n            expr => Ok(Self::Expr(Box::new(expr))),\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/derive_props/builder.rs",
    "content": "//! The `PropsBuilder` constructs props in alphabetical order and enforces that required props have\n//! been set before allowing the build to complete. Each property has a corresponding method in the\n//! builder. Required property builder methods advance the builder to the next step, optional\n//! properties can be added or skipped with no effect on the build step. Once all of required\n//! properties have been set, the builder moves to the final build step which implements the\n//! `build()` method.\n\nuse proc_macro2::{Ident, Span};\nuse quote::{format_ident, quote, ToTokens};\nuse syn::{parse_quote_spanned, Attribute, GenericParam};\n\nuse super::generics::to_arguments;\nuse super::DerivePropsInput;\nuse crate::derive_props::generics::push_type_param;\n\npub struct PropsBuilder<'a> {\n    builder_name: &'a Ident,\n    props: &'a DerivePropsInput,\n    wrapper_name: &'a Ident,\n    check_all_props_name: &'a Ident,\n    extra_attrs: &'a [Attribute],\n}\n\nimpl ToTokens for PropsBuilder<'_> {\n    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {\n        let Self {\n            builder_name,\n            props,\n            wrapper_name,\n            ..\n        } = self;\n\n        let DerivePropsInput { vis, generics, .. } = props;\n\n        let assert_all_props = self.impl_assert_props();\n\n        let (_, ty_generics, where_clause) = generics.split_for_impl();\n\n        let builder = quote! {\n            #[doc(hidden)]\n            #vis struct #builder_name #generics\n                #where_clause\n            {\n                wrapped: ::std::boxed::Box<#wrapper_name #ty_generics>,\n            }\n\n            #assert_all_props\n        };\n\n        tokens.extend(builder);\n    }\n}\n\nimpl<'a> PropsBuilder<'_> {\n    pub fn new(\n        name: &'a Ident,\n        props: &'a DerivePropsInput,\n        wrapper_name: &'a Ident,\n        check_all_props_name: &'a Ident,\n        extra_attrs: &'a [Attribute],\n    ) -> PropsBuilder<'a> {\n        PropsBuilder {\n            builder_name: name,\n            props,\n            wrapper_name,\n            check_all_props_name,\n            extra_attrs,\n        }\n    }\n}\n\nimpl PropsBuilder<'_> {\n    fn set_fields(&self) -> impl Iterator<Item = impl ToTokens + '_> {\n        self.props.prop_fields.iter().map(|pf| pf.to_field_setter())\n    }\n\n    fn impl_assert_props(&self) -> proc_macro2::TokenStream {\n        let Self {\n            builder_name,\n            check_all_props_name,\n            extra_attrs,\n            ..\n        } = self;\n        let DerivePropsInput {\n            vis,\n            generics,\n            props_name,\n            prop_fields,\n            ..\n        } = self.props;\n\n        let set_fields = self.set_fields();\n        let prop_fns = prop_fields\n            .iter()\n            .map(|pf| pf.to_build_step_fn(vis, props_name));\n\n        let (builder_impl_generics, ty_generics, builder_where_clause) = generics.split_for_impl();\n        let turbofish_generics = ty_generics.as_turbofish();\n        let generic_args = to_arguments(generics);\n\n        let mut assert_impl_generics = generics.clone();\n        let token_arg: GenericParam = parse_quote_spanned! {Span::mixed_site()=>\n            __YewToken\n        };\n        push_type_param(&mut assert_impl_generics, token_arg.clone());\n        let assert_impl_generics = assert_impl_generics;\n        let (impl_generics, _, where_clause) = assert_impl_generics.split_for_impl();\n\n        let props_mod_name = format_ident!(\"_{}\", props_name, span = Span::mixed_site());\n        let mut check_impl_generics = assert_impl_generics.clone();\n        let mut check_args = vec![];\n        let mut check_props = proc_macro2::TokenStream::new();\n        let prop_field_decls = prop_fields\n            .iter()\n            .map(|pf| pf.to_field_check(props_name, vis, &token_arg))\n            .collect::<Vec<_>>();\n        let prop_name_decls = prop_field_decls.iter().map(|pf| pf.to_fake_prop_decl());\n        for pf in prop_field_decls.iter() {\n            check_props.extend(pf.to_stream(\n                &mut check_impl_generics,\n                &mut check_args,\n                &props_mod_name,\n            ));\n        }\n        let (check_impl_generics, _, check_where_clause) = check_impl_generics.split_for_impl();\n\n        quote! {\n            #[automatically_derived]\n            #( #extra_attrs )*\n            impl #builder_impl_generics #builder_name<#generic_args> #builder_where_clause {\n                #( #prop_fns )*\n            }\n\n            #[doc(hidden)]\n            #[allow(non_snake_case)]\n            #vis mod #props_mod_name {\n                #( #prop_name_decls )*\n            }\n            #check_props\n\n            #[doc(hidden)]\n            #vis struct #check_all_props_name<How>(::std::marker::PhantomData<How>);\n\n            #[automatically_derived]\n            #[diagnostic::do_not_recommend]\n            impl<B, P, How> ::yew::html::HasProp<P, &dyn ::yew::html::HasProp<P, How>>\n                for #check_all_props_name<B>\n                where B: ::yew::html::HasProp<P, How> {}\n\n            #[automatically_derived]\n            #[diagnostic::do_not_recommend]\n            impl #check_impl_generics ::yew::html::HasAllProps<\n                #props_name #ty_generics ,\n                ( #( #check_args , )* ),\n            > for #check_all_props_name< #token_arg > #check_where_clause {\n            }\n\n            #[automatically_derived]\n            impl #impl_generics ::yew::html::Buildable< #token_arg > for #builder_name<#generic_args> #where_clause {\n                type Output = #props_name #ty_generics;\n                type WrappedToken = #check_all_props_name< #token_arg >;\n                fn build(this: Self) -> Self::Output {\n                    #props_name #turbofish_generics {\n                        #(#set_fields)*\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/derive_props/field.rs",
    "content": "use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};\nuse std::convert::TryFrom;\n\nuse proc_macro2::{Ident, Span};\nuse quote::{format_ident, quote, quote_spanned};\nuse syn::parse::Result;\nuse syn::spanned::Spanned;\nuse syn::{\n    parse_quote, Attribute, Error, Expr, Field, GenericArgument, GenericParam, Generics,\n    PathArguments, Type, Visibility,\n};\n\nuse super::should_preserve_attr;\nuse crate::derive_props::generics::push_type_param;\n\nfn is_option_type(ty: &Type) -> bool {\n    if let Type::Path(type_path) = ty {\n        if let Some(segment) = type_path.path.segments.last() {\n            if segment.ident == \"Option\" {\n                if let PathArguments::AngleBracketed(args) = &segment.arguments {\n                    return args.args.len() == 1\n                        && matches!(args.args.first(), Some(GenericArgument::Type(_)));\n                }\n            }\n        }\n    }\n    false\n}\n\n#[allow(clippy::large_enum_variant)]\n#[derive(PartialEq, Eq)]\npub enum PropAttr {\n    Required { wrapped_name: Ident },\n    PropOr(Expr),\n    PropOrElse(Expr),\n    PropOrDefault,\n}\n\n#[derive(Eq)]\npub struct PropField {\n    pub ty: Type,\n    name: Ident,\n    pub attr: PropAttr,\n    extra_attrs: Vec<Attribute>,\n}\n\nimpl PropField {\n    /// All required property fields are wrapped in an `Option`\n    pub fn is_required(&self) -> bool {\n        matches!(self.attr, PropAttr::Required { .. })\n    }\n\n    /// This check name is descriptive to help a developer realize they missed a required prop\n    fn to_check_name(&self, props_name: &Ident) -> Ident {\n        format_ident!(\"Has{}{}\", props_name, self.name, span = Span::mixed_site())\n    }\n\n    /// This check name is descriptive to help a developer realize they missed a required prop\n    fn to_check_arg_name(&self, props_name: &Ident) -> GenericParam {\n        let ident = format_ident!(\"How{}{}\", props_name, self.name, span = Span::mixed_site());\n        GenericParam::Type(ident.into())\n    }\n\n    /// Ident of the wrapped field name\n    fn wrapped_name(&self) -> &Ident {\n        match &self.attr {\n            PropAttr::Required { wrapped_name } => wrapped_name,\n            _ => &self.name,\n        }\n    }\n\n    pub fn to_field_check<'a>(\n        &'a self,\n        props_name: &'a Ident,\n        vis: &'a Visibility,\n        token: &'a GenericParam,\n    ) -> PropFieldCheck<'a> {\n        let check_struct = self.to_check_name(props_name);\n        let check_arg = self.to_check_arg_name(props_name);\n        PropFieldCheck {\n            this: self,\n            vis,\n            token,\n            check_struct,\n            check_arg,\n        }\n    }\n\n    /// Used to transform the `PropWrapper` struct into `Properties`\n    pub fn to_field_setter(&self) -> proc_macro2::TokenStream {\n        let name = &self.name;\n        let setter = match &self.attr {\n            PropAttr::Required { wrapped_name } => {\n                quote! {\n                    #name: ::std::option::Option::unwrap(this.wrapped.#wrapped_name),\n                }\n            }\n            PropAttr::PropOr(value) => {\n                quote_spanned! {value.span()=>\n                    #name: ::std::option::Option::unwrap_or(this.wrapped.#name, #value),\n                }\n            }\n            PropAttr::PropOrElse(func) => {\n                quote_spanned! {func.span()=>\n                    #name: ::std::option::Option::unwrap_or_else(this.wrapped.#name, #func),\n                }\n            }\n            PropAttr::PropOrDefault => {\n                quote! {\n                    #name: ::std::option::Option::unwrap_or_default(this.wrapped.#name),\n                }\n            }\n        };\n        let extra_attrs = &self.extra_attrs;\n        quote! {\n            #( #extra_attrs )*\n            #setter\n        }\n    }\n\n    /// Wrap all required props in `Option`\n    pub fn to_field_def(&self) -> proc_macro2::TokenStream {\n        let ty = &self.ty;\n        let extra_attrs = &self.extra_attrs;\n        let wrapped_name = self.wrapped_name();\n        quote! {\n            #( #extra_attrs )*\n            #wrapped_name: ::std::option::Option<#ty>,\n        }\n    }\n\n    /// All optional props must implement the `Default` trait\n    pub fn to_default_setter(&self) -> proc_macro2::TokenStream {\n        let wrapped_name = self.wrapped_name();\n        let extra_attrs = &self.extra_attrs;\n        quote! {\n            #( #extra_attrs )*\n            #wrapped_name: ::std::option::Option::None,\n        }\n    }\n\n    /// Each field is set using a builder method\n    pub fn to_build_step_fn(\n        &self,\n        vis: &Visibility,\n        props_name: &Ident,\n    ) -> proc_macro2::TokenStream {\n        let Self { name, ty, attr, .. } = self;\n        let token_ty = Ident::new(\"__YewTokenTy\", Span::mixed_site());\n        let none_fn_name = format_ident!(\"{}_none\", name, span = Span::mixed_site());\n        let build_fn = match attr {\n            PropAttr::Required { wrapped_name } => {\n                let check_struct = self.to_check_name(props_name);\n                let none_setter = if is_option_type(ty) {\n                    quote! {\n                        #[doc(hidden)]\n                        #vis fn #none_fn_name<#token_ty>(\n                            &mut self,\n                            token: #token_ty,\n                        ) -> #check_struct< #token_ty > {\n                            self.wrapped.#wrapped_name = ::std::option::Option::Some(::std::option::Option::None);\n                            #check_struct ( ::std::marker::PhantomData )\n                        }\n                    }\n                } else {\n                    quote! {}\n                };\n                quote! {\n                    #[doc(hidden)]\n                    #vis fn #name<#token_ty>(\n                        &mut self,\n                        token: #token_ty,\n                        value: impl ::yew::html::IntoPropValue<#ty>,\n                    ) -> #check_struct< #token_ty > {\n                        self.wrapped.#wrapped_name = ::std::option::Option::Some(value.into_prop_value());\n                        #check_struct ( ::std::marker::PhantomData )\n                    }\n\n                    #none_setter\n                }\n            }\n            _ => {\n                let none_setter = if is_option_type(ty) {\n                    quote! {\n                        #[doc(hidden)]\n                        #vis fn #none_fn_name<#token_ty>(\n                            &mut self,\n                            token: #token_ty,\n                        ) -> #token_ty {\n                            self.wrapped.#name = ::std::option::Option::Some(::std::option::Option::None);\n                            token\n                        }\n                    }\n                } else {\n                    quote! {}\n                };\n                quote! {\n                    #[doc(hidden)]\n                    #vis fn #name<#token_ty>(\n                        &mut self,\n                        token: #token_ty,\n                        value: impl ::yew::html::IntoPropValue<#ty>,\n                    ) -> #token_ty {\n                        self.wrapped.#name = ::std::option::Option::Some(value.into_prop_value());\n                        token\n                    }\n\n                    #none_setter\n                }\n            }\n        };\n        let extra_attrs = &self.extra_attrs;\n        quote! {\n            #( #extra_attrs )*\n            #build_fn\n        }\n    }\n\n    // Detect Properties 2.0 attributes\n    fn attribute(named_field: &Field) -> Result<PropAttr> {\n        let attr = named_field.attrs.iter().find(|attr| {\n            attr.path().is_ident(\"prop_or\")\n                || attr.path().is_ident(\"prop_or_else\")\n                || attr.path().is_ident(\"prop_or_default\")\n        });\n\n        if let Some(attr) = attr {\n            if attr.path().is_ident(\"prop_or\") {\n                Ok(PropAttr::PropOr(attr.parse_args()?))\n            } else if attr.path().is_ident(\"prop_or_else\") {\n                Ok(PropAttr::PropOrElse(attr.parse_args()?))\n            } else if attr.path().is_ident(\"prop_or_default\") {\n                Ok(PropAttr::PropOrDefault)\n            } else {\n                unreachable!()\n            }\n        } else {\n            let ident = named_field.ident.as_ref().unwrap();\n            let wrapped_name = format_ident!(\"{}_wrapper\", ident, span = Span::mixed_site());\n            Ok(PropAttr::Required { wrapped_name })\n        }\n    }\n}\n\npub struct PropFieldCheck<'a> {\n    this: &'a PropField,\n    vis: &'a Visibility,\n    token: &'a GenericParam,\n    check_struct: Ident,\n    check_arg: GenericParam,\n}\n\nimpl PropFieldCheck<'_> {\n    pub fn to_fake_prop_decl(&self) -> proc_macro2::TokenStream {\n        let Self { this, .. } = self;\n        if !this.is_required() {\n            return Default::default();\n        }\n        let mut prop_check_name = this.name.clone();\n        prop_check_name.set_span(Span::mixed_site());\n        quote! {\n            #[allow(non_camel_case_types)]\n            pub struct #prop_check_name;\n        }\n    }\n\n    pub fn to_stream(\n        &self,\n        type_generics: &mut Generics,\n        check_args: &mut Vec<GenericParam>,\n        prop_name_mod: &Ident,\n    ) -> proc_macro2::TokenStream {\n        let Self {\n            this,\n            vis,\n            token,\n            check_struct,\n            check_arg,\n        } = self;\n        if !this.is_required() {\n            return Default::default();\n        }\n        let mut prop_check_name = this.name.clone();\n        prop_check_name.set_span(Span::mixed_site());\n        check_args.push(check_arg.clone());\n        push_type_param(type_generics, check_arg.clone());\n        let where_clause = type_generics.make_where_clause();\n        where_clause.predicates.push(parse_quote! {\n            #token: ::yew::html::HasProp< #prop_name_mod :: #prop_check_name, #check_arg >\n        });\n\n        quote! {\n            #[doc(hidden)]\n            #[allow(non_camel_case_types)]\n            #vis struct #check_struct<How>(::std::marker::PhantomData<How>);\n\n            #[automatically_derived]\n            #[diagnostic::do_not_recommend]\n            impl<B> ::yew::html::HasProp< #prop_name_mod :: #prop_check_name, #check_struct<B>>\n                for #check_struct<B> {}\n\n            #[automatically_derived]\n            #[diagnostic::do_not_recommend]\n            impl<B, P, How> ::yew::html::HasProp<P, &dyn ::yew::html::HasProp<P, How>>\n                for #check_struct<B>\n                where B: ::yew::html::HasProp<P, How> {}\n\n        }\n    }\n}\n\nimpl TryFrom<Field> for PropField {\n    type Error = Error;\n\n    fn try_from(field: Field) -> Result<Self> {\n        let extra_attrs = field\n            .attrs\n            .iter()\n            .filter(|a| should_preserve_attr(a))\n            .cloned()\n            .collect();\n\n        Ok(PropField {\n            attr: Self::attribute(&field)?,\n            extra_attrs,\n            ty: field.ty,\n            name: field.ident.unwrap(),\n        })\n    }\n}\n\nimpl PartialOrd for PropField {\n    fn partial_cmp(&self, other: &PropField) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for PropField {\n    fn cmp(&self, other: &PropField) -> Ordering {\n        if self.name == other.name {\n            Ordering::Equal\n        } else if self.name == \"children\" {\n            Ordering::Greater\n        } else if other.name == \"children\" {\n            Ordering::Less\n        } else {\n            self.name.cmp(&other.name)\n        }\n    }\n}\n\nimpl PartialEq for PropField {\n    fn eq(&self, other: &Self) -> bool {\n        self.name == other.name\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/derive_props/generics.rs",
    "content": "use proc_macro2::Ident;\nuse syn::punctuated::Punctuated;\nuse syn::{GenericArgument, GenericParam, Generics, Path, Token, Type, TypePath};\n\n/// Alias for a comma-separated list of `GenericArgument`\npub type GenericArguments = Punctuated<GenericArgument, Token![,]>;\n\n/// Finds the index of the first generic param with a default value or a const generic.\nfn first_default_or_const_param_position(generics: &Generics) -> Option<usize> {\n    generics.params.iter().position(|param| match param {\n        GenericParam::Type(param) => param.default.is_some(),\n        GenericParam::Const(_) => true,\n        _ => false,\n    })\n}\n\n/// Push a type GenericParam into a Generics\npub fn push_type_param(generics: &mut Generics, type_param: GenericParam) {\n    if let Some(idx) = first_default_or_const_param_position(generics) {\n        generics.params.insert(idx, type_param)\n    } else {\n        generics.params.push(type_param)\n    }\n}\n\n/// Converts `GenericParams` into `GenericArguments`.\npub fn to_arguments(generics: &Generics) -> GenericArguments {\n    let mut args: GenericArguments = Punctuated::new();\n    args.extend(generics.params.iter().map(|param| match param {\n        GenericParam::Type(type_param) => new_generic_type_arg(type_param.ident.clone()),\n        GenericParam::Lifetime(lifetime_param) => {\n            GenericArgument::Lifetime(lifetime_param.lifetime.clone())\n        }\n        GenericParam::Const(const_param) => new_generic_type_arg(const_param.ident.clone()),\n    }));\n    args\n}\n\n// Creates a `GenericArgument` from an `Ident`\nfn new_generic_type_arg(ident: Ident) -> GenericArgument {\n    GenericArgument::Type(Type::Path(TypePath {\n        path: Path::from(ident),\n        qself: None,\n    }))\n}\n"
  },
  {
    "path": "packages/yew-macro/src/derive_props/mod.rs",
    "content": "mod builder;\nmod field;\nmod generics;\nmod wrapper;\n\nuse std::convert::TryInto;\n\nuse builder::PropsBuilder;\nuse field::PropField;\nuse proc_macro2::{Ident, Span};\nuse quote::{format_ident, quote, ToTokens};\nuse syn::parse::{Parse, ParseStream, Result};\nuse syn::punctuated::Pair;\nuse syn::visit_mut::VisitMut;\nuse syn::{\n    AngleBracketedGenericArguments, Attribute, ConstParam, DeriveInput, GenericArgument,\n    GenericParam, Generics, Path, PathArguments, PathSegment, Type, TypeParam, TypePath,\n    Visibility,\n};\nuse wrapper::PropsWrapper;\n\nuse self::field::PropAttr;\nuse self::generics::to_arguments;\n\npub struct DerivePropsInput {\n    vis: Visibility,\n    generics: Generics,\n    props_name: Ident,\n    prop_fields: Vec<PropField>,\n    preserved_attrs: Vec<Attribute>,\n}\n\n/// AST visitor that replaces all occurrences of the keyword `Self` with `new_self`\nstruct Normaliser<'ast> {\n    new_self: &'ast Ident,\n    generics: &'ast Generics,\n    /// `Option` for one-time initialisation\n    new_self_full: Option<PathSegment>,\n}\n\nimpl<'ast> Normaliser<'ast> {\n    pub fn new(new_self: &'ast Ident, generics: &'ast Generics) -> Self {\n        Self {\n            new_self,\n            generics,\n            new_self_full: None,\n        }\n    }\n\n    fn get_new_self(&mut self) -> PathSegment {\n        self.new_self_full\n            .get_or_insert_with(|| {\n                PathSegment {\n                    ident: self.new_self.clone(),\n                    arguments: if self.generics.lt_token.is_some() {\n                        PathArguments::AngleBracketed(AngleBracketedGenericArguments {\n                            colon2_token: Some(Default::default()),\n                            lt_token: Default::default(),\n                            args: self\n                                .generics\n                                .params\n                                .pairs()\n                                .map(|pair| {\n                                    let (value, punct) = pair.cloned().into_tuple();\n                                    let value = match value {\n                                        GenericParam::Lifetime(param) => {\n                                            GenericArgument::Lifetime(param.lifetime)\n                                        }\n                                        GenericParam::Type(TypeParam { ident, .. })\n                                        | GenericParam::Const(ConstParam { ident, .. }) => {\n                                            GenericArgument::Type(Type::Path(TypePath {\n                                                qself: None,\n                                                path: ident.into(),\n                                            }))\n                                        }\n                                    };\n                                    Pair::new(value, punct)\n                                })\n                                .collect(),\n                            gt_token: Default::default(),\n                        })\n                    } else {\n                        // if no generics were defined for the struct\n                        PathArguments::None\n                    },\n                }\n            })\n            .clone()\n    }\n}\n\nimpl VisitMut for Normaliser<'_> {\n    fn visit_path_mut(&mut self, path: &mut Path) {\n        if let Some(first) = path.segments.first_mut() {\n            if first.ident == \"Self\" {\n                *first = self.get_new_self();\n            }\n            syn::visit_mut::visit_path_mut(self, path)\n        }\n    }\n}\n\n/// Some attributes on the original struct are to be preserved and added to the builder struct,\n/// in order to avoid warnings (sometimes reported as errors) in the output.\nfn should_preserve_attr(attr: &Attribute) -> bool {\n    // #[cfg(...)]: does not usually appear in macro inputs, but rust-analyzer seems to generate it\n    // sometimes.              If not preserved, results in \"no-such-field\" errors generating\n    // the field setter for `build` #[allow(...)]: silences warnings from clippy, such as\n    // dead_code etc. #[deny(...)]: enable additional warnings from clippy\n    let path = attr.path();\n    path.is_ident(\"allow\") || path.is_ident(\"deny\") || path.is_ident(\"cfg\")\n}\n\nimpl Parse for DerivePropsInput {\n    fn parse(input: ParseStream) -> Result<Self> {\n        let input: DeriveInput = input.parse()?;\n        let prop_fields = match input.data {\n            syn::Data::Struct(data) => match data.fields {\n                syn::Fields::Named(fields) => {\n                    let mut prop_fields: Vec<PropField> = fields\n                        .named\n                        .into_iter()\n                        .map(|f| f.try_into())\n                        .collect::<Result<Vec<PropField>>>()?;\n\n                    // Alphabetize\n                    prop_fields.sort();\n\n                    prop_fields\n                }\n                syn::Fields::Unit => Vec::new(),\n                _ => unimplemented!(\"only structs are supported\"),\n            },\n            _ => unimplemented!(\"only structs are supported\"),\n        };\n\n        let preserved_attrs = input\n            .attrs\n            .iter()\n            .filter(|a| should_preserve_attr(a))\n            .cloned()\n            .collect();\n\n        Ok(Self {\n            vis: input.vis,\n            props_name: input.ident,\n            generics: input.generics,\n            prop_fields,\n            preserved_attrs,\n        })\n    }\n}\n\nimpl DerivePropsInput {\n    /// Replaces all occurrences of `Self` in the struct with the actual name of the struct.\n    /// Must be called before tokenising the struct.\n    pub fn normalise(&mut self) {\n        let mut normaliser = Normaliser::new(&self.props_name, &self.generics);\n        for field in &mut self.prop_fields {\n            normaliser.visit_type_mut(&mut field.ty);\n            if let PropAttr::PropOr(expr) | PropAttr::PropOrElse(expr) = &mut field.attr {\n                normaliser.visit_expr_mut(expr)\n            }\n        }\n    }\n}\n\nimpl ToTokens for DerivePropsInput {\n    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {\n        let Self {\n            generics,\n            props_name,\n            prop_fields,\n            preserved_attrs,\n            ..\n        } = self;\n\n        // The wrapper is a new struct which wraps required props in `Option`\n        let wrapper_name = format_ident!(\"{}Wrapper\", props_name, span = Span::mixed_site());\n        let wrapper = PropsWrapper::new(&wrapper_name, generics, prop_fields, preserved_attrs);\n        tokens.extend(wrapper.into_token_stream());\n\n        // The builder will only build if all required props have been set\n        let builder_name = format_ident!(\"{}Builder\", props_name, span = Span::mixed_site());\n        let check_all_props_name =\n            format_ident!(\"Check{}All\", props_name, span = Span::mixed_site());\n        let builder = PropsBuilder::new(\n            &builder_name,\n            self,\n            &wrapper_name,\n            &check_all_props_name,\n            preserved_attrs,\n        );\n        let generic_args = to_arguments(generics);\n        tokens.extend(builder.into_token_stream());\n\n        // The properties trait has a `builder` method which creates the props builder\n        let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();\n        let properties = quote! {\n            impl #impl_generics ::yew::html::Properties for #props_name #ty_generics #where_clause {\n                type Builder = #builder_name<#generic_args>;\n\n                fn builder() -> Self::Builder {\n                    #builder_name {\n                        wrapped: ::std::boxed::Box::new(::std::default::Default::default()),\n                    }\n                }\n            }\n        };\n        tokens.extend(properties);\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/derive_props/wrapper.rs",
    "content": "use proc_macro2::Ident;\nuse quote::{quote, ToTokens};\nuse syn::{Attribute, Generics};\n\nuse super::PropField;\n\npub struct PropsWrapper<'a> {\n    wrapper_name: &'a Ident,\n    generics: &'a Generics,\n    prop_fields: &'a [PropField],\n    extra_attrs: &'a [Attribute],\n}\n\nimpl ToTokens for PropsWrapper<'_> {\n    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {\n        let Self {\n            generics,\n            wrapper_name,\n            extra_attrs,\n            ..\n        } = self;\n\n        let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();\n        let turbofish_generics = ty_generics.as_turbofish();\n\n        let wrapper_field_defs = self.field_defs();\n        let wrapper_default_setters = self.default_setters();\n\n        let wrapper = quote! {\n            #[doc(hidden)]\n            #(#extra_attrs)*\n            struct #wrapper_name #generics\n                #where_clause\n            {\n                #(#wrapper_field_defs)*\n            }\n\n            #[automatically_derived]\n            impl #impl_generics ::std::default::Default for #wrapper_name #ty_generics #where_clause {\n                fn default() -> Self {\n                    #wrapper_name #turbofish_generics {\n                        #(#wrapper_default_setters)*\n                    }\n                }\n            }\n        };\n        wrapper.to_tokens(tokens);\n    }\n}\n\nimpl<'a> PropsWrapper<'a> {\n    pub fn new(\n        name: &'a Ident,\n        generics: &'a Generics,\n        prop_fields: &'a [PropField],\n        extra_attrs: &'a [Attribute],\n    ) -> Self {\n        PropsWrapper {\n            wrapper_name: name,\n            generics,\n            prop_fields,\n            extra_attrs,\n        }\n    }\n\n    fn field_defs(&self) -> impl Iterator<Item = impl ToTokens + '_> {\n        self.prop_fields.iter().map(|pf| pf.to_field_def())\n    }\n\n    fn default_setters(&self) -> impl Iterator<Item = impl ToTokens + '_> {\n        self.prop_fields.iter().map(|pf| pf.to_default_setter())\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/function_component.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse quote::{quote, ToTokens};\nuse syn::parse::{Parse, ParseStream};\nuse syn::punctuated::Punctuated;\nuse syn::token::{Comma, Fn};\nuse syn::{\n    parse_quote, parse_quote_spanned, visit_mut, Attribute, Block, FnArg, Generics, Ident, Item,\n    ItemFn, LitStr, ReturnType, Type, Visibility,\n};\n\nuse crate::hook::BodyRewriter;\n\n#[derive(Clone)]\npub struct FunctionComponent {\n    block: Box<Block>,\n    props_type: Box<Type>,\n    arg: FnArg,\n    generics: Generics,\n    vis: Visibility,\n    attrs: Vec<Attribute>,\n    name: Ident,\n    return_type: Box<Type>,\n    fn_token: Fn,\n\n    component_name: Option<Ident>,\n}\n\nimpl Parse for FunctionComponent {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let parsed: Item = input.parse()?;\n\n        let func = match parsed {\n            Item::Fn(m) => m,\n\n            item => {\n                return Err(syn::Error::new_spanned(\n                    item,\n                    \"`component` attribute can only be applied to functions\",\n                ))\n            }\n        };\n\n        let ItemFn {\n            attrs,\n            vis,\n            sig,\n            block,\n        } = func;\n\n        if sig.generics.lifetimes().next().is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.generics,\n                \"function components can't have generic lifetime parameters\",\n            ));\n        }\n\n        if sig.asyncness.is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.asyncness,\n                \"function components can't be async\",\n            ));\n        }\n\n        if sig.constness.is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.constness,\n                \"const functions can't be function components\",\n            ));\n        }\n\n        if sig.abi.is_some() {\n            return Err(syn::Error::new_spanned(\n                sig.abi,\n                \"extern functions can't be function components\",\n            ));\n        }\n\n        let return_type = match sig.output {\n            ReturnType::Default => {\n                return Err(syn::Error::new_spanned(\n                    sig,\n                    \"function components must return `yew::Html` or `yew::HtmlResult`\",\n                ))\n            }\n            ReturnType::Type(_, ty) => ty,\n        };\n\n        let mut inputs = sig.inputs.into_iter();\n        let arg = inputs\n            .next()\n            .unwrap_or_else(|| syn::parse_quote! { _: &() });\n\n        let ty = match &arg {\n            FnArg::Typed(arg) => match &*arg.ty {\n                Type::Reference(ty) => {\n                    if ty.lifetime.is_some() {\n                        return Err(syn::Error::new_spanned(\n                            &ty.lifetime,\n                            \"reference must not have a lifetime\",\n                        ));\n                    }\n\n                    if ty.mutability.is_some() {\n                        return Err(syn::Error::new_spanned(\n                            ty.mutability,\n                            \"reference must not be mutable\",\n                        ));\n                    }\n\n                    ty.elem.clone()\n                }\n                ty => {\n                    let msg = format!(\n                        \"expected a reference to a `Properties` type (try: `&{}`)\",\n                        ty.to_token_stream()\n                    );\n                    return Err(syn::Error::new_spanned(ty, msg));\n                }\n            },\n\n            FnArg::Receiver(_) => {\n                return Err(syn::Error::new_spanned(\n                    arg,\n                    \"function components can't accept a receiver\",\n                ));\n            }\n        };\n\n        // Checking after param parsing may make it a little inefficient\n        // but that's a requirement for better error messages in case of receivers\n        // `>0` because first one is already consumed.\n        if inputs.len() > 0 {\n            let params: TokenStream = inputs.map(|it| it.to_token_stream()).collect();\n            return Err(syn::Error::new_spanned(\n                params,\n                \"function components can accept at most one parameter for the props\",\n            ));\n        }\n\n        Ok(Self {\n            props_type: ty,\n            block,\n            arg,\n            generics: sig.generics,\n            vis,\n            attrs,\n            name: sig.ident,\n            return_type,\n            fn_token: sig.fn_token,\n            component_name: None,\n        })\n    }\n}\n\nimpl FunctionComponent {\n    /// Filters attributes that should be copied to component definition.\n    fn filter_attrs_for_component_struct(&self) -> Vec<Attribute> {\n        self.attrs\n            .iter()\n            .filter_map(|m| {\n                m.path()\n                    .get_ident()\n                    .and_then(|ident| match ident.to_string().as_str() {\n                        \"doc\" | \"allow\" => Some(m.clone()),\n                        _ => None,\n                    })\n            })\n            .collect()\n    }\n\n    /// Filters attributes that should be copied to the component impl block.\n    fn filter_attrs_for_component_impl(&self) -> Vec<Attribute> {\n        self.attrs\n            .iter()\n            .filter_map(|m| {\n                m.path()\n                    .get_ident()\n                    .and_then(|ident| match ident.to_string().as_str() {\n                        \"allow\" => Some(m.clone()),\n                        _ => None,\n                    })\n            })\n            .collect()\n    }\n\n    fn phantom_generics(&self) -> Punctuated<Ident, Comma> {\n        self.generics\n            .type_params()\n            .map(|ty_param| ty_param.ident.clone()) // create a new Punctuated sequence without any type bounds\n            .collect::<Punctuated<_, Comma>>()\n    }\n\n    fn merge_component_name(&mut self, name: FunctionComponentName) -> syn::Result<()> {\n        if let Some(ref m) = name.component_name {\n            if m == &self.name {\n                return Err(syn::Error::new_spanned(\n                    m,\n                    \"the component must not have the same name as the function\",\n                ));\n            }\n        }\n\n        self.component_name = name.component_name;\n\n        Ok(())\n    }\n\n    fn inner_fn_ident(&self) -> Ident {\n        if self.component_name.is_some() {\n            self.name.clone()\n        } else {\n            Ident::new(\"inner\", Span::mixed_site())\n        }\n    }\n\n    fn component_name(&self) -> Ident {\n        self.component_name\n            .clone()\n            .unwrap_or_else(|| self.name.clone())\n    }\n\n    // We need to cast 'static on all generics for base component.\n    fn create_static_component_generics(&self) -> Generics {\n        let mut generics = self.generics.clone();\n\n        let where_clause = generics.make_where_clause();\n        for ty_generic in self.generics.type_params() {\n            let ident = &ty_generic.ident;\n            let bound = parse_quote_spanned! { ident.span() =>\n                #ident: 'static\n            };\n\n            where_clause.predicates.push(bound);\n        }\n\n        where_clause.predicates.push(parse_quote! { Self: 'static });\n\n        generics\n    }\n\n    /// Prints the impl fn.\n    fn print_inner_fn(&self) -> TokenStream {\n        let name = self.inner_fn_ident();\n        let FunctionComponent {\n            ref fn_token,\n            ref attrs,\n            ref block,\n            ref return_type,\n            ref generics,\n            ref arg,\n            ..\n        } = self;\n        let mut block = *block.clone();\n        let (impl_generics, _ty_generics, where_clause) = generics.split_for_impl();\n\n        // We use _ctx here so if the component does not use any hooks, the unused_vars lint will\n        // not be triggered.\n        let ctx_ident = Ident::new(\"_ctx\", Span::mixed_site());\n\n        let mut body_rewriter = BodyRewriter::new(ctx_ident.clone());\n        visit_mut::visit_block_mut(&mut body_rewriter, &mut block);\n\n        quote! {\n            #(#attrs)*\n            #fn_token #name #impl_generics (#ctx_ident: &mut ::yew::functional::HookContext, #arg) -> #return_type\n            #where_clause\n            {\n                #block\n            }\n        }\n    }\n\n    fn print_base_component_impl(&self) -> TokenStream {\n        let component_name = self.component_name();\n        let props_type = &self.props_type;\n        let static_comp_generics = self.create_static_component_generics();\n\n        let (impl_generics, ty_generics, where_clause) = static_comp_generics.split_for_impl();\n\n        // TODO: replace with blanket implementation when specialisation becomes stable.\n        quote! {\n            #[automatically_derived]\n            impl #impl_generics ::yew::html::BaseComponent for #component_name #ty_generics #where_clause {\n                type Message = ();\n                type Properties = #props_type;\n\n                #[inline]\n                fn create(ctx: &::yew::html::Context<Self>) -> Self {\n                    Self {\n                        _marker: ::std::marker::PhantomData,\n                        function_component: ::yew::functional::FunctionComponent::<Self>::new(ctx),\n                    }\n                }\n\n                #[inline]\n                fn update(&mut self, _ctx: &::yew::html::Context<Self>, _msg: Self::Message) -> ::std::primitive::bool {\n                    true\n                }\n\n                #[inline]\n                fn changed(&mut self, _ctx: &::yew::html::Context<Self>, _old_props: &Self::Properties) -> ::std::primitive::bool {\n                    true\n                }\n\n                #[inline]\n                fn view(&self, ctx: &::yew::html::Context<Self>) -> ::yew::html::HtmlResult {\n                    ::yew::functional::FunctionComponent::<Self>::render(\n                        &self.function_component,\n                        ::yew::html::Context::<Self>::props(ctx)\n                    )\n                }\n\n                #[inline]\n                fn rendered(&mut self, _ctx: &::yew::html::Context<Self>, _first_render: ::std::primitive::bool) {\n                    ::yew::functional::FunctionComponent::<Self>::rendered(&self.function_component)\n                }\n\n                #[inline]\n                fn destroy(&mut self, _ctx: &::yew::html::Context<Self>) {\n                    ::yew::functional::FunctionComponent::<Self>::destroy(&self.function_component)\n                }\n\n                #[inline]\n                fn prepare_state(&self) -> ::std::option::Option<::std::string::String> {\n                    ::yew::functional::FunctionComponent::<Self>::prepare_state(&self.function_component)\n                }\n            }\n        }\n    }\n\n    fn print_debug_impl(&self) -> TokenStream {\n        let component_name = self.component_name();\n        let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();\n\n        let component_name_lit = LitStr::new(&format!(\"{component_name}<_>\"), Span::mixed_site());\n\n        quote! {\n            #[automatically_derived]\n            impl #impl_generics ::std::fmt::Debug for #component_name #ty_generics #where_clause {\n                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {\n                    ::std::write!(f, #component_name_lit)\n                }\n            }\n        }\n    }\n\n    fn print_fn_provider_impl(&self) -> TokenStream {\n        let func = self.print_inner_fn();\n        let component_impl_attrs = self.filter_attrs_for_component_impl();\n        let component_name = self.component_name();\n        let fn_name = self.inner_fn_ident();\n        let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();\n        let props_type = &self.props_type;\n        let fn_generics = ty_generics.as_turbofish();\n\n        let component_props = Ident::new(\"props\", Span::mixed_site());\n        let ctx_ident = Ident::new(\"ctx\", Span::mixed_site());\n\n        quote! {\n            // we cannot disable any lints here because it will be applied to the function body\n            // as well.\n            #(#component_impl_attrs)*\n            impl #impl_generics ::yew::functional::FunctionProvider for #component_name #ty_generics #where_clause {\n                type Properties = #props_type;\n\n                fn run(#ctx_ident: &mut ::yew::functional::HookContext, #component_props: &Self::Properties) -> ::yew::html::HtmlResult {\n                    #func\n\n                    ::yew::html::IntoHtmlResult::into_html_result(#fn_name #fn_generics (#ctx_ident, #component_props))\n                }\n            }\n        }\n    }\n\n    fn print_struct_def(&self) -> TokenStream {\n        let component_attrs = self.filter_attrs_for_component_struct();\n        let component_name = self.component_name();\n\n        let generics = &self.generics;\n        let (_impl_generics, _ty_generics, where_clause) = self.generics.split_for_impl();\n        let phantom_generics = self.phantom_generics();\n        let vis = &self.vis;\n\n        quote! {\n            #(#component_attrs)*\n            #[allow(unused_parens)]\n            #vis struct #component_name #generics #where_clause {\n                _marker: ::std::marker::PhantomData<(#phantom_generics)>,\n                function_component: ::yew::functional::FunctionComponent<Self>,\n            }\n        }\n    }\n}\n\npub struct FunctionComponentName {\n    component_name: Option<Ident>,\n}\n\nimpl Parse for FunctionComponentName {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        if input.is_empty() {\n            return Ok(Self {\n                component_name: None,\n            });\n        }\n\n        let component_name = input.parse()?;\n\n        Ok(Self {\n            component_name: Some(component_name),\n        })\n    }\n}\n\npub fn function_component_impl(\n    name: FunctionComponentName,\n    mut component: FunctionComponent,\n) -> syn::Result<TokenStream> {\n    component.merge_component_name(name)?;\n\n    let base_comp_impl = component.print_base_component_impl();\n    let debug_impl = component.print_debug_impl();\n    let provider_fn_impl = component.print_fn_provider_impl();\n    let struct_def = component.print_struct_def();\n\n    let quoted = quote! {\n        #struct_def\n\n        #provider_fn_impl\n        #debug_impl\n        #base_comp_impl\n    };\n\n    Ok(quoted)\n}\n"
  },
  {
    "path": "packages/yew-macro/src/hook/body.rs",
    "content": "use std::sync::{Arc, Mutex};\n\nuse proc_macro_error::emit_error;\nuse syn::spanned::Spanned;\nuse syn::visit_mut::VisitMut;\nuse syn::{\n    parse_quote_spanned, visit_mut, Expr, ExprCall, ExprClosure, ExprForLoop, ExprIf, ExprLoop,\n    ExprMatch, ExprWhile, Ident, Item,\n};\n\n#[derive(Debug)]\npub struct BodyRewriter {\n    branch_lock: Arc<Mutex<()>>,\n    ctx_ident: Ident,\n}\n\nimpl BodyRewriter {\n    pub fn new(ctx_ident: Ident) -> Self {\n        Self {\n            branch_lock: Arc::default(),\n            ctx_ident,\n        }\n    }\n\n    fn is_branched(&self) -> bool {\n        self.branch_lock.try_lock().is_err()\n    }\n\n    fn with_branch<F, O>(&mut self, f: F) -> O\n    where\n        F: FnOnce(&mut BodyRewriter) -> O,\n    {\n        let branch_lock = self.branch_lock.clone();\n        let _branched = branch_lock.try_lock();\n        f(self)\n    }\n}\n\nimpl VisitMut for BodyRewriter {\n    fn visit_expr_call_mut(&mut self, i: &mut ExprCall) {\n        let ctx_ident = &self.ctx_ident;\n\n        // Only rewrite hook calls.\n        if let Expr::Path(ref m) = &*i.func {\n            if let Some(m) = m.path.segments.last().as_ref().map(|m| &m.ident) {\n                if m.to_string().starts_with(\"use_\") {\n                    if self.is_branched() {\n                        emit_error!(\n                            m,\n                            \"hooks cannot be called at this position.\";\n                            help = \"move hooks to the top-level of your function.\";\n                            note = \"see: https://yew.rs/docs/next/concepts/function-components/hooks\"\n                        );\n                    } else {\n                        *i = parse_quote_spanned! { i.span() => ::yew::functional::Hook::run(#i, #ctx_ident) };\n                    }\n\n                    return;\n                }\n            }\n        }\n\n        visit_mut::visit_expr_call_mut(self, i);\n    }\n\n    fn visit_expr_mut(&mut self, i: &mut Expr) {\n        let ctx_ident = &self.ctx_ident;\n\n        match &mut *i {\n            Expr::Macro(m) => {\n                if let Some(ident) = m.mac.path.segments.last().as_ref().map(|m| &m.ident) {\n                    if ident.to_string().starts_with(\"use_\") {\n                        if self.is_branched() {\n                            emit_error!(\n                                ident,\n                                \"hooks cannot be called at this position.\";\n                                help = \"move hooks to the top-level of your function.\";\n                                note = \"see: https://yew.rs/docs/next/concepts/function-components/hooks\"\n                            );\n                        } else {\n                            *i = parse_quote_spanned! { i.span() => ::yew::functional::Hook::run(#i, #ctx_ident) };\n                        }\n                    } else {\n                        visit_mut::visit_expr_macro_mut(self, m);\n                    }\n                }\n            }\n            _ => visit_mut::visit_expr_mut(self, i),\n        }\n    }\n\n    fn visit_expr_closure_mut(&mut self, i: &mut ExprClosure) {\n        self.with_branch(move |m| visit_mut::visit_expr_closure_mut(m, i))\n    }\n\n    fn visit_expr_if_mut(&mut self, i: &mut ExprIf) {\n        for it in &mut i.attrs {\n            visit_mut::visit_attribute_mut(self, it);\n        }\n\n        visit_mut::visit_expr_mut(self, &mut i.cond);\n\n        self.with_branch(|m| visit_mut::visit_block_mut(m, &mut i.then_branch));\n\n        if let Some(it) = &mut i.else_branch {\n            self.with_branch(|m| visit_mut::visit_expr_mut(m, &mut (it).1));\n        }\n    }\n\n    fn visit_expr_loop_mut(&mut self, i: &mut ExprLoop) {\n        self.with_branch(|m| visit_mut::visit_expr_loop_mut(m, i));\n    }\n\n    fn visit_expr_for_loop_mut(&mut self, i: &mut ExprForLoop) {\n        for it in &mut i.attrs {\n            visit_mut::visit_attribute_mut(self, it);\n        }\n        if let Some(it) = &mut i.label {\n            visit_mut::visit_label_mut(self, it);\n        }\n        visit_mut::visit_pat_mut(self, &mut i.pat);\n        visit_mut::visit_expr_mut(self, &mut i.expr);\n\n        self.with_branch(|m| visit_mut::visit_block_mut(m, &mut i.body));\n    }\n\n    fn visit_expr_match_mut(&mut self, i: &mut ExprMatch) {\n        for it in &mut i.attrs {\n            visit_mut::visit_attribute_mut(self, it);\n        }\n\n        visit_mut::visit_expr_mut(self, &mut i.expr);\n\n        self.with_branch(|m| {\n            for it in &mut i.arms {\n                visit_mut::visit_arm_mut(m, it);\n            }\n        });\n    }\n\n    fn visit_expr_while_mut(&mut self, i: &mut ExprWhile) {\n        for it in &mut i.attrs {\n            visit_mut::visit_attribute_mut(self, it);\n        }\n        if let Some(it) = &mut i.label {\n            visit_mut::visit_label_mut(self, it);\n        }\n\n        self.with_branch(|m| visit_mut::visit_expr_mut(m, &mut i.cond));\n        self.with_branch(|m| visit_mut::visit_block_mut(m, &mut i.body));\n    }\n\n    fn visit_item_mut(&mut self, _i: &mut Item) {\n        // We don't do anything for items.\n        // for components / hooks in other components / hooks, apply the attribute again.\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/hook/lifetime.rs",
    "content": "use std::sync::{Arc, Mutex};\n\nuse proc_macro2::Span;\nuse syn::visit_mut::{self, VisitMut};\nuse syn::{\n    GenericArgument, Lifetime, ParenthesizedGenericArguments, Receiver, TypeBareFn, TypeImplTrait,\n    TypeParamBound, TypeReference, TypeTraitObject,\n};\n\n// borrowed from the awesome async-trait crate.\npub struct CollectLifetimes {\n    pub elided: Vec<Lifetime>,\n    pub name: &'static str,\n    pub default_span: Span,\n\n    pub type_trait_obj_lock: Arc<Mutex<()>>,\n    pub impl_trait_lock: Arc<Mutex<()>>,\n    pub impl_fn_lock: Arc<Mutex<()>>,\n}\n\nimpl CollectLifetimes {\n    pub fn new(name: &'static str, default_span: Span) -> Self {\n        CollectLifetimes {\n            elided: Vec::new(),\n            name,\n            default_span,\n\n            impl_trait_lock: Arc::default(),\n            type_trait_obj_lock: Arc::default(),\n            impl_fn_lock: Arc::default(),\n        }\n    }\n\n    fn is_impl_trait(&self) -> bool {\n        self.impl_trait_lock.try_lock().is_err()\n    }\n\n    fn is_type_trait_obj(&self) -> bool {\n        self.type_trait_obj_lock.try_lock().is_err()\n    }\n\n    fn is_impl_fn(&self) -> bool {\n        self.impl_fn_lock.try_lock().is_err()\n    }\n\n    fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {\n        match lifetime {\n            None => *lifetime = Some(self.next_lifetime(None)),\n            Some(lifetime) => self.visit_lifetime(lifetime),\n        }\n    }\n\n    fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {\n        if lifetime.ident == \"_\" {\n            *lifetime = self.next_lifetime(lifetime.span());\n        }\n    }\n\n    fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {\n        let name = format!(\"{}{}\", self.name, self.elided.len());\n        let span = span.into().unwrap_or(self.default_span);\n        let life = Lifetime::new(&name, span);\n        self.elided.push(life.clone());\n        life\n    }\n}\n\nimpl VisitMut for CollectLifetimes {\n    fn visit_receiver_mut(&mut self, arg: &mut Receiver) {\n        if let Some((_, lifetime)) = &mut arg.reference {\n            self.visit_opt_lifetime(lifetime);\n        }\n    }\n\n    fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {\n        // We don't rewrite references in the impl FnOnce(&arg) or fn(&arg)\n        if self.is_impl_fn() {\n            return;\n        }\n\n        self.visit_opt_lifetime(&mut ty.lifetime);\n        visit_mut::visit_type_reference_mut(self, ty);\n    }\n\n    fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) {\n        // We don't rewrite types in the impl FnOnce(&arg) -> Type<'_>\n        if self.is_impl_fn() {\n            return;\n        }\n\n        if let GenericArgument::Lifetime(lifetime) = gen {\n            self.visit_lifetime(lifetime);\n        }\n        visit_mut::visit_generic_argument_mut(self, gen);\n    }\n\n    fn visit_type_impl_trait_mut(&mut self, impl_trait: &mut TypeImplTrait) {\n        let impl_trait_lock = self.impl_trait_lock.clone();\n        let _locked = impl_trait_lock.try_lock();\n\n        impl_trait\n            .bounds\n            .insert(0, TypeParamBound::Lifetime(self.next_lifetime(None)));\n\n        visit_mut::visit_type_impl_trait_mut(self, impl_trait);\n    }\n\n    fn visit_type_trait_object_mut(&mut self, type_trait_obj: &mut TypeTraitObject) {\n        let type_trait_obj_lock = self.type_trait_obj_lock.clone();\n        let _locked = type_trait_obj_lock.try_lock();\n\n        visit_mut::visit_type_trait_object_mut(self, type_trait_obj);\n    }\n\n    fn visit_parenthesized_generic_arguments_mut(\n        &mut self,\n        generic_args: &mut ParenthesizedGenericArguments,\n    ) {\n        let impl_fn_lock = self.impl_fn_lock.clone();\n        let _maybe_locked =\n            (self.is_impl_trait() || self.is_type_trait_obj()).then(|| impl_fn_lock.try_lock());\n\n        visit_mut::visit_parenthesized_generic_arguments_mut(self, generic_args);\n    }\n\n    fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) {\n        let impl_fn_lock = self.impl_fn_lock.clone();\n        let _locked = impl_fn_lock.try_lock();\n\n        visit_mut::visit_type_bare_fn_mut(self, i);\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/hook/mod.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse proc_macro_error::emit_error;\nuse quote::quote;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{\n    visit_mut, AttrStyle, Attribute, Block, Expr, ExprPath, File, Ident, Item, ItemFn, LitStr,\n    Meta, MetaNameValue, ReturnType, Signature, Stmt, Token, Type,\n};\n\nmod body;\nmod lifetime;\nmod signature;\n\npub use body::BodyRewriter;\nuse signature::HookSignature;\n\n#[derive(Clone)]\npub struct HookFn {\n    inner: ItemFn,\n}\n\nimpl Parse for HookFn {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let func: ItemFn = input.parse()?;\n\n        let sig = func.sig.clone();\n\n        if sig.asyncness.is_some() {\n            emit_error!(sig.asyncness, \"async functions can't be hooks\");\n        }\n\n        if sig.constness.is_some() {\n            emit_error!(sig.constness, \"const functions can't be hooks\");\n        }\n\n        if sig.abi.is_some() {\n            emit_error!(sig.abi, \"extern functions can't be hooks\");\n        }\n\n        if sig.unsafety.is_some() {\n            emit_error!(sig.unsafety, \"unsafe functions can't be hooks\");\n        }\n\n        if !sig.ident.to_string().starts_with(\"use_\") {\n            emit_error!(sig.ident, \"hooks must have a name starting with `use_`\");\n        }\n\n        Ok(Self { inner: func })\n    }\n}\n\nimpl HookFn {\n    fn doc_attr(&self) -> Attribute {\n        let span = self.inner.span();\n\n        let sig_formatted = prettyplease::unparse(&File {\n            shebang: None,\n            attrs: vec![],\n            items: vec![Item::Fn(ItemFn {\n                block: Box::new(Block {\n                    brace_token: Default::default(),\n                    stmts: vec![Stmt::Expr(\n                        Expr::Path(ExprPath {\n                            attrs: vec![],\n                            qself: None,\n                            path: Ident::new(\"__yew_macro_dummy_function_body__\", span).into(),\n                        }),\n                        None,\n                    )],\n                }),\n                ..self.inner.clone()\n            })],\n        });\n\n        let literal = LitStr::new(\n            &format!(\n                r#\"\n# Note\n\nWhen used in function components and hooks, this hook is equivalent to:\n\n```\n{}\n```\n\"#,\n                sig_formatted.replace(\n                    \"__yew_macro_dummy_function_body__\",\n                    \"/* implementation omitted */\"\n                )\n            ),\n            span,\n        );\n\n        Attribute {\n            pound_token: Default::default(),\n            style: AttrStyle::Outer,\n            bracket_token: Default::default(),\n            meta: Meta::NameValue(MetaNameValue {\n                path: Ident::new(\"doc\", span).into(),\n                eq_token: Token![=](span),\n                value: Expr::Lit(syn::ExprLit {\n                    attrs: vec![],\n                    lit: literal.into(),\n                }),\n            }),\n        }\n    }\n}\n\npub fn hook_impl(hook: HookFn) -> syn::Result<TokenStream> {\n    let doc_attr = hook.doc_attr();\n\n    let HookFn { inner: original_fn } = hook;\n\n    let ItemFn {\n        ref vis,\n        ref sig,\n        ref block,\n        ref attrs,\n    } = original_fn;\n    let mut block = *block.clone();\n\n    let hook_sig = HookSignature::rewrite(sig);\n\n    let Signature {\n        ref fn_token,\n        ref ident,\n        ref inputs,\n        output: ref hook_return_type,\n        ref generics,\n        ..\n    } = hook_sig.sig;\n\n    let output_type = &hook_sig.output_type;\n\n    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();\n    let call_generics = hook_sig.call_generics();\n\n    // We use _ctx so that if a hook does not use other hooks, it will not trigger unused_vars.\n    let ctx_ident = Ident::new(\"_ctx\", Span::mixed_site());\n\n    let mut body_rewriter = BodyRewriter::new(ctx_ident.clone());\n    visit_mut::visit_block_mut(&mut body_rewriter, &mut block);\n\n    let inner_fn_ident = Ident::new(\"inner_fn\", Span::mixed_site());\n    let input_args = hook_sig.input_args();\n\n    let inner_fn_rt = match &sig.output {\n        ReturnType::Default => None,\n        ReturnType::Type(rarrow, _) => Some(quote! { #rarrow #output_type }),\n    };\n\n    let output_is_impl_trait = matches!(hook_sig.output_type, Type::ImplTrait(_));\n\n    let inner_fn = if output_is_impl_trait {\n        quote! {}\n    } else {\n        quote! { fn #inner_fn_ident #generics (#ctx_ident: &mut ::yew::functional::HookContext, #inputs) #inner_fn_rt #where_clause #block }\n    };\n\n    let inner_type_impl = if hook_sig.needs_boxing {\n        let hook_lifetime = &hook_sig.hook_lifetime;\n        let boxed_inner_ident = Ident::new(\"boxed_inner\", Span::mixed_site());\n\n        if output_is_impl_trait {\n            quote! {\n                let #boxed_inner_ident = ::std::boxed::Box::new(\n                        move |#ctx_ident: &mut ::yew::functional::HookContext| #block\n                    );\n\n                ::yew::functional::BoxedHook::<#hook_lifetime,>::new(#boxed_inner_ident)\n            }\n        } else {\n            let hook_lifetime_plus = quote! { #hook_lifetime + };\n            let boxed_fn_type = quote! { ::std::boxed::Box<dyn #hook_lifetime_plus ::std::ops::FnOnce(&mut ::yew::functional::HookContext) #inner_fn_rt> };\n            let as_boxed_fn = quote! { as #boxed_fn_type };\n            let generic_types = generics.type_params().map(|t| &t.ident);\n\n            quote! {\n                let #boxed_inner_ident = ::std::boxed::Box::new(\n                        move |#ctx_ident: &mut ::yew::functional::HookContext| #inner_fn_rt {\n                            #inner_fn_ident :: <#(#generic_types,)*> (#ctx_ident, #(#input_args,)*)\n                        }\n                    ) #as_boxed_fn;\n\n                ::yew::functional::BoxedHook::<#hook_lifetime, #output_type>::new(#boxed_inner_ident)\n            }\n        }\n    } else {\n        let input_types = hook_sig.input_types();\n\n        let args_ident = Ident::new(\"args\", Span::mixed_site());\n        let hook_struct_name = Ident::new(\"HookProvider\", Span::mixed_site());\n\n        let phantom_types = hook_sig.phantom_types();\n        let phantom_lifetimes = hook_sig.phantom_lifetimes();\n\n        quote! {\n            struct #hook_struct_name #generics #where_clause {\n                _marker: ::std::marker::PhantomData<( #(#phantom_types,)* #(#phantom_lifetimes,)* )>,\n                #args_ident: (#(#input_types,)*),\n            }\n\n            #[automatically_derived]\n            impl #impl_generics ::yew::functional::Hook for #hook_struct_name #ty_generics #where_clause {\n                type Output = #output_type;\n\n                fn run(mut self, #ctx_ident: &mut ::yew::functional::HookContext) -> Self::Output {\n                    let (#(#input_args,)*) = self.#args_ident;\n\n                    #inner_fn_ident #call_generics (#ctx_ident, #(#input_args,)*)\n                }\n            }\n\n            #[automatically_derived]\n            impl #impl_generics #hook_struct_name #ty_generics #where_clause {\n                fn new(#inputs) -> Self {\n                   #hook_struct_name {\n                        _marker: ::std::marker::PhantomData,\n                        #args_ident: (#(#input_args,)*),\n                    }\n                }\n            }\n\n            #hook_struct_name #call_generics ::new(#(#input_args,)*)\n        }\n    };\n\n    // There're some weird issues with doc tests that it cannot detect return types properly.\n    // So we print original implementation instead.\n    let output = quote! {\n        #[cfg(not(doctest))]\n        #(#attrs)*\n        #doc_attr\n        #vis #fn_token #ident #generics (#inputs) #hook_return_type #where_clause {\n            #inner_fn\n\n            #inner_type_impl\n        }\n\n        #[cfg(doctest)]\n        #original_fn\n    };\n\n    Ok(output)\n}\n"
  },
  {
    "path": "packages/yew-macro/src/hook/signature.rs",
    "content": "use std::iter::once;\nuse std::mem::take;\n\nuse proc_macro2::{Span, TokenStream};\nuse proc_macro_error::emit_error;\nuse quote::{quote, ToTokens};\nuse syn::punctuated::{Pair, Punctuated};\nuse syn::spanned::Spanned;\nuse syn::visit_mut::VisitMut;\nuse syn::{\n    parse_quote, parse_quote_spanned, visit_mut, FnArg, GenericParam, Ident, Lifetime,\n    LifetimeParam, Pat, Receiver, ReturnType, Signature, Type, TypeImplTrait, TypeParam,\n    TypeParamBound, TypeReference, WherePredicate,\n};\n\nuse super::lifetime;\n\nfn type_is_generic(ty: &Type, param: &TypeParam) -> bool {\n    match ty {\n        Type::Path(path) => path.path.is_ident(&param.ident),\n        _ => false,\n    }\n}\n\n#[derive(Default)]\npub struct CollectArgs {\n    needs_boxing: bool,\n}\n\nimpl CollectArgs {\n    pub fn new() -> Self {\n        Self::default()\n    }\n}\n\nimpl VisitMut for CollectArgs {\n    fn visit_type_impl_trait_mut(&mut self, impl_trait: &mut TypeImplTrait) {\n        self.needs_boxing = true;\n\n        visit_mut::visit_type_impl_trait_mut(self, impl_trait);\n    }\n\n    fn visit_receiver_mut(&mut self, recv: &mut Receiver) {\n        emit_error!(recv, \"methods cannot be hooks\");\n\n        visit_mut::visit_receiver_mut(self, recv);\n    }\n}\n\npub struct HookSignature {\n    pub hook_lifetime: Lifetime,\n    pub sig: Signature,\n    pub output_type: Type,\n    pub needs_boxing: bool,\n}\n\nimpl HookSignature {\n    fn rewrite_return_type(hook_lifetime: &Lifetime, rt_type: &ReturnType) -> (ReturnType, Type) {\n        let bound = quote! { #hook_lifetime + };\n\n        match rt_type {\n            ReturnType::Default => (\n                parse_quote! { -> impl #bound ::yew::functional::Hook<Output = ()> },\n                parse_quote! { () },\n            ),\n            ReturnType::Type(arrow, ref return_type) => {\n                if let Type::Reference(ref m) = &**return_type {\n                    if m.lifetime.is_none() {\n                        let mut return_type_ref = m.clone();\n                        return_type_ref.lifetime = parse_quote!('hook);\n\n                        let return_type_ref = Type::Reference(return_type_ref);\n\n                        return (\n                            parse_quote_spanned! {\n                                return_type.span() => #arrow impl #bound ::yew::functional::Hook<Output = #return_type_ref>\n                            },\n                            return_type_ref,\n                        );\n                    }\n                }\n\n                (\n                    parse_quote_spanned! {\n                        return_type.span() => #arrow impl #bound ::yew::functional::Hook<Output = #return_type>\n                    },\n                    *return_type.clone(),\n                )\n            }\n        }\n    }\n\n    /// Rewrites a Hook Signature and extracts information.\n    pub fn rewrite(sig: &Signature) -> Self {\n        let mut sig = sig.clone();\n\n        let mut arg_info = CollectArgs::new();\n        arg_info.visit_signature_mut(&mut sig);\n\n        let mut lifetimes = lifetime::CollectLifetimes::new(\"'arg\", sig.ident.span());\n        for arg in sig.inputs.iter_mut() {\n            match arg {\n                FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),\n                FnArg::Typed(arg) => lifetimes.visit_type_mut(&mut arg.ty),\n            }\n        }\n\n        let Signature {\n            ref mut generics,\n            output: ref return_type,\n            ..\n        } = sig;\n\n        let hook_lifetime = Lifetime::new(\"'hook\", Span::mixed_site());\n        let mut params: Punctuated<_, _> = once(hook_lifetime.clone())\n            .chain(lifetimes.elided)\n            .map(|lifetime| {\n                GenericParam::Lifetime(LifetimeParam {\n                    attrs: vec![],\n                    lifetime,\n                    colon_token: None,\n                    bounds: Default::default(),\n                })\n            })\n            .map(|param| Pair::new(param, Some(Default::default())))\n            .chain(take(&mut generics.params).into_pairs())\n            .collect();\n\n        for type_param in params.iter_mut().skip(1) {\n            match type_param {\n                GenericParam::Lifetime(param) => {\n                    if let Some(predicate) = generics\n                        .where_clause\n                        .iter_mut()\n                        .flat_map(|c| &mut c.predicates)\n                        .find_map(|predicate| match predicate {\n                            WherePredicate::Lifetime(p) if p.lifetime == param.lifetime => Some(p),\n                            _ => None,\n                        })\n                    {\n                        predicate.bounds.push(hook_lifetime.clone());\n                    } else {\n                        param.colon_token = Some(param.colon_token.unwrap_or_default());\n                        param.bounds.push(hook_lifetime.clone());\n                    }\n                }\n\n                GenericParam::Type(param) => {\n                    if let Some(predicate) = generics\n                        .where_clause\n                        .iter_mut()\n                        .flat_map(|c| &mut c.predicates)\n                        .find_map(|predicate| match predicate {\n                            WherePredicate::Type(p) if type_is_generic(&p.bounded_ty, param) => {\n                                Some(p)\n                            }\n                            _ => None,\n                        })\n                    {\n                        predicate\n                            .bounds\n                            .push(TypeParamBound::Lifetime(hook_lifetime.clone()));\n                    } else {\n                        param.colon_token = Some(param.colon_token.unwrap_or_default());\n                        param\n                            .bounds\n                            .push(TypeParamBound::Lifetime(hook_lifetime.clone()));\n                    }\n                }\n\n                GenericParam::Const(_) => {}\n            }\n        }\n\n        generics.params = params;\n\n        let (output, output_type) = Self::rewrite_return_type(&hook_lifetime, return_type);\n        sig.output = output;\n\n        Self {\n            hook_lifetime,\n            sig,\n            output_type,\n            needs_boxing: arg_info.needs_boxing,\n        }\n    }\n\n    pub fn phantom_types(&self) -> Vec<Ident> {\n        self.sig\n            .generics\n            .type_params()\n            .map(|ty_param| ty_param.ident.clone())\n            .collect()\n    }\n\n    pub fn phantom_lifetimes(&self) -> Vec<TypeReference> {\n        self.sig\n            .generics\n            .lifetimes()\n            .map(|life| TypeReference {\n                and_token: Default::default(),\n                lifetime: Some(life.lifetime.clone()),\n                mutability: None,\n                elem: Box::new(Type::Tuple(syn::TypeTuple {\n                    paren_token: Default::default(),\n                    elems: Default::default(),\n                })),\n            })\n            .collect()\n    }\n\n    pub fn input_args(&self) -> Vec<Ident> {\n        self.sig\n            .inputs\n            .iter()\n            .filter_map(|m| {\n                if let FnArg::Typed(m) = m {\n                    if let Pat::Ident(ref m) = *m.pat {\n                        return Some(m.ident.clone());\n                    }\n                }\n\n                None\n            })\n            .collect()\n    }\n\n    pub fn input_types(&self) -> Vec<Type> {\n        self.sig\n            .inputs\n            .iter()\n            .filter_map(|m| {\n                if let FnArg::Typed(m) = m {\n                    return Some(*m.ty.clone());\n                }\n\n                None\n            })\n            .collect()\n    }\n\n    pub fn call_generics(&self) -> TokenStream {\n        let mut generics = self.sig.generics.clone();\n\n        // We need to filter out lifetimes.\n        generics.params = generics\n            .params\n            .into_iter()\n            .filter(|m| !matches!(m, GenericParam::Lifetime(_)))\n            .collect();\n\n        let (_impl_generics, ty_generics, _where_clause) = generics.split_for_impl();\n        ty_generics.as_turbofish().to_token_stream()\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_block.rs",
    "content": "use proc_macro2::Delimiter;\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream};\nuse syn::{braced, token};\n\nuse super::{HtmlIterable, HtmlNode, ToNodeIterator};\nuse crate::PeekValue;\n\npub struct HtmlBlock {\n    pub content: BlockContent,\n    brace: token::Brace,\n}\n\npub enum BlockContent {\n    Node(Box<HtmlNode>),\n    Iterable(Box<HtmlIterable>),\n}\n\nimpl PeekValue<()> for HtmlBlock {\n    fn peek(cursor: Cursor) -> Option<()> {\n        cursor.group(Delimiter::Brace).map(|_| ())\n    }\n}\n\nimpl Parse for HtmlBlock {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let content;\n        let brace = braced!(content in input);\n        let content = if HtmlIterable::peek(content.cursor()).is_some() {\n            BlockContent::Iterable(Box::new(content.parse()?))\n        } else {\n            BlockContent::Node(Box::new(content.parse()?))\n        };\n\n        Ok(HtmlBlock { content, brace })\n    }\n}\n\nimpl ToTokens for HtmlBlock {\n    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {\n        let HtmlBlock { content, .. } = self;\n        let new_tokens = match content {\n            BlockContent::Iterable(html_iterable) => quote! {#html_iterable},\n            BlockContent::Node(html_node) => quote! {#html_node},\n        };\n\n        tokens.extend(quote! {#new_tokens});\n    }\n}\n\nimpl ToNodeIterator for HtmlBlock {\n    fn to_node_iterator_stream(&self) -> Option<proc_macro2::TokenStream> {\n        let HtmlBlock { content, brace } = self;\n        let new_tokens = match content {\n            BlockContent::Iterable(iterable) => iterable.to_node_iterator_stream(),\n            BlockContent::Node(node) => node.to_node_iterator_stream(),\n        }?;\n\n        Some(quote_spanned! {brace.span=> #new_tokens})\n    }\n\n    fn is_singular(&self) -> bool {\n        match &self.content {\n            BlockContent::Node(node) => node.is_singular(),\n            BlockContent::Iterable(_) => false,\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_component.rs",
    "content": "use proc_macro2::Span;\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::parse::discouraged::Speculative;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{Token, Type};\n\nuse super::{HtmlChildrenTree, TagTokens};\nuse crate::is_ide_completion;\nuse crate::props::ComponentProps;\n\npub struct HtmlComponent {\n    ty: Type,\n    pub props: ComponentProps,\n    children: HtmlChildrenTree,\n    close: Option<HtmlComponentClose>,\n}\n\nimpl Parse for HtmlComponent {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        // check if the next tokens are </\n        let trying_to_close = || {\n            let lt = input.peek(Token![<]);\n            let div = input.peek2(Token![/]);\n            lt && div\n        };\n\n        if trying_to_close() {\n            let close = input.parse::<HtmlComponentClose>();\n            if !is_ide_completion() {\n                return match close {\n                    Ok(close) => Err(syn::Error::new_spanned(\n                        close.to_spanned(),\n                        \"this closing tag has no corresponding opening tag\",\n                    )),\n                    Err(err) => Err(err),\n                };\n            }\n        }\n\n        let open = input.parse::<HtmlComponentOpen>()?;\n        // Return early if it's a self-closing tag\n        if open.is_self_closing() {\n            return Ok(HtmlComponent {\n                ty: open.ty,\n                props: open.props,\n                children: HtmlChildrenTree::new(),\n                close: None,\n            });\n        }\n\n        let mut children = HtmlChildrenTree::new();\n        let close = loop {\n            if input.is_empty() {\n                if is_ide_completion() {\n                    break None;\n                }\n                return Err(syn::Error::new_spanned(\n                    open.to_spanned(),\n                    \"this opening tag has no corresponding closing tag\",\n                ));\n            }\n\n            if trying_to_close() {\n                fn format_token_stream(ts: impl ToTokens) -> String {\n                    let string = ts.to_token_stream().to_string();\n                    // remove unnecessary spaces\n                    string.replace(' ', \"\")\n                }\n\n                let fork = input.fork();\n                let close = TagTokens::parse_end_content(&fork, |i_fork, tag| {\n                    let ty = i_fork.parse().map_err(|e| {\n                        syn::Error::new(\n                            e.span(),\n                            format!(\n                                \"expected a valid closing tag for component\\nnote: found opening \\\n                                 tag `{lt}{0}{gt}`\\nhelp: try `{lt}/{0}{gt}`\",\n                                format_token_stream(&open.ty),\n                                lt = open.tag.lt.to_token_stream(),\n                                gt = open.tag.gt.to_token_stream(),\n                            ),\n                        )\n                    })?;\n\n                    if ty != open.ty && !is_ide_completion() {\n                        let open_ty = &open.ty;\n                        Err(syn::Error::new_spanned(\n                            quote!(#open_ty #ty),\n                            format!(\n                                \"mismatched closing tags: expected `{}`, found `{}`\",\n                                format_token_stream(open_ty),\n                                format_token_stream(ty)\n                            ),\n                        ))\n                    } else {\n                        let close = HtmlComponentClose { tag, ty };\n                        input.advance_to(&fork);\n                        Ok(close)\n                    }\n                })?;\n                break Some(close);\n            }\n            children.parse_child(input)?;\n        };\n\n        if !children.is_empty() {\n            if let Some(children_prop) = open.props.children() {\n                return Err(syn::Error::new_spanned(\n                    &children_prop.label,\n                    \"cannot specify the `children` prop when the component already has children\",\n                ));\n            }\n        }\n\n        Ok(HtmlComponent {\n            ty: open.ty,\n            props: open.props,\n            children,\n            close,\n        })\n    }\n}\n\nimpl ToTokens for HtmlComponent {\n    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {\n        let Self {\n            ty,\n            props,\n            children,\n            close,\n        } = self;\n\n        let ty_span = ty.span().resolved_at(Span::call_site());\n        let props_ty = quote_spanned!(ty_span=> <#ty as ::yew::html::BaseComponent>::Properties);\n        let children_renderer = children.to_children_renderer_tokens();\n        let build_props = props.build_properties_tokens(&props_ty, children_renderer);\n        let key = props.special().wrap_key_attr();\n        let use_close_tag = close\n            .as_ref()\n            .map(|close| {\n                let close_ty = &close.ty;\n                quote_spanned! {close_ty.span()=>\n                    let _ = |_:#close_ty| {};\n                }\n            })\n            .unwrap_or_default();\n\n        tokens.extend(quote_spanned! {ty_span=>\n            {\n                #use_close_tag\n                #[allow(clippy::let_unit_value)]\n                let __yew_props = #build_props;\n                ::yew::virtual_dom::VChild::<#ty>::new(__yew_props, #key)\n            }\n        });\n    }\n}\n\nstruct HtmlComponentOpen {\n    tag: TagTokens,\n    ty: Type,\n    props: ComponentProps,\n}\nimpl HtmlComponentOpen {\n    fn is_self_closing(&self) -> bool {\n        self.tag.div.is_some()\n    }\n\n    fn to_spanned(&self) -> impl ToTokens {\n        self.tag.to_spanned()\n    }\n}\n\nimpl Parse for HtmlComponentOpen {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        TagTokens::parse_start_content(input, |input, tag| {\n            let ty = input.parse()?;\n            let props: ComponentProps = input.parse()?;\n\n            if let Some(ref node_ref) = props.special().node_ref {\n                return Err(syn::Error::new_spanned(\n                    &node_ref.label,\n                    \"cannot use `ref` with components. If you want to specify a property, use \\\n                     `r#ref` here instead.\",\n                ));\n            }\n\n            Ok(Self { tag, ty, props })\n        })\n    }\n}\n\nstruct HtmlComponentClose {\n    tag: TagTokens,\n    ty: Type,\n}\nimpl HtmlComponentClose {\n    fn to_spanned(&self) -> impl ToTokens {\n        self.tag.to_spanned()\n    }\n}\n\nimpl Parse for HtmlComponentClose {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        TagTokens::parse_end_content(input, |input, tag| {\n            let ty = input.parse()?;\n            Ok(Self { tag, ty })\n        })\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_dashed_name.rs",
    "content": "use std::fmt;\n\nuse proc_macro2::{Ident, Span, TokenStream};\nuse quote::{quote, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::ext::IdentExt;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{LitStr, Token};\n\nuse crate::stringify::Stringify;\nuse crate::{non_capitalized_ascii, Peek};\n\n#[derive(Clone, PartialEq, Eq)]\npub struct HtmlDashedName {\n    pub name: Ident,\n    pub extended: Vec<(Token![-], Ident)>,\n}\n\nimpl HtmlDashedName {\n    /// Checks if this name is equal to the provided item (which can be anything implementing\n    /// `Into<String>`).\n    pub fn eq_ignore_ascii_case<S>(&self, other: S) -> bool\n    where\n        S: Into<String>,\n    {\n        let mut s = other.into();\n        s.make_ascii_lowercase();\n        s == self.to_ascii_lowercase_string()\n    }\n\n    pub fn to_ascii_lowercase_string(&self) -> String {\n        let mut s = self.to_string();\n        s.make_ascii_lowercase();\n        s\n    }\n\n    pub fn to_lit_str(&self) -> LitStr {\n        LitStr::new(&self.to_string(), self.span())\n    }\n}\n\nimpl fmt::Display for HtmlDashedName {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{}\", self.name)?;\n        for (_, ident) in &self.extended {\n            write!(f, \"-{ident}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl Peek<'_, Self> for HtmlDashedName {\n    fn peek(cursor: Cursor) -> Option<(Self, Cursor)> {\n        let (name, cursor) = cursor.ident()?;\n        if !non_capitalized_ascii(&name.to_string()) {\n            return None;\n        }\n\n        let mut extended = Vec::new();\n        let mut cursor = cursor;\n        loop {\n            if let Some((punct, p_cursor)) = cursor.punct() {\n                if punct.as_char() == '-' {\n                    let (ident, i_cursor) = p_cursor.ident()?;\n                    cursor = i_cursor;\n                    extended.push((Token![-](Span::mixed_site()), ident));\n                    continue;\n                }\n            }\n            break;\n        }\n\n        Some((HtmlDashedName { name, extended }, cursor))\n    }\n}\n\nimpl Parse for HtmlDashedName {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let name = input.call(Ident::parse_any)?;\n        let mut extended = Vec::new();\n        while input.peek(Token![-]) {\n            extended.push((input.parse::<Token![-]>()?, input.call(Ident::parse_any)?));\n        }\n\n        Ok(HtmlDashedName { name, extended })\n    }\n}\n\nimpl ToTokens for HtmlDashedName {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let HtmlDashedName { name, extended } = self;\n        let dashes = extended.iter().map(|(dash, _)| quote! {#dash});\n        let idents = extended.iter().map(|(_, ident)| quote! {#ident});\n        let extended = quote! { #(#dashes #idents)* };\n        tokens.extend(quote! { #name #extended });\n    }\n}\n\nimpl Stringify for HtmlDashedName {\n    fn try_into_lit(&self) -> Option<LitStr> {\n        Some(self.to_lit_str())\n    }\n\n    fn stringify(&self) -> TokenStream {\n        self.to_lit_str().stringify()\n    }\n}\n\nimpl From<Ident> for HtmlDashedName {\n    fn from(name: Ident) -> Self {\n        HtmlDashedName {\n            name,\n            extended: vec![],\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_element.rs",
    "content": "use proc_macro2::{Delimiter, Group, Span, TokenStream};\nuse proc_macro_error::emit_warning;\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{Expr, Ident, Lit, LitStr, Token};\n\nuse super::{HtmlChildrenTree, HtmlDashedName, TagTokens};\nuse crate::props::{ElementProps, Prop, PropDirective};\nuse crate::stringify::{Stringify, Value};\nuse crate::{is_ide_completion, non_capitalized_ascii, Peek, PeekValue};\n\nfn is_normalised_element_name(name: &str) -> bool {\n    match name {\n        \"animateMotion\"\n        | \"animateTransform\"\n        | \"clipPath\"\n        | \"feBlend\"\n        | \"feColorMatrix\"\n        | \"feComponentTransfer\"\n        | \"feComposite\"\n        | \"feConvolveMatrix\"\n        | \"feDiffuseLighting\"\n        | \"feDisplacementMap\"\n        | \"feDistantLight\"\n        | \"feDropShadow\"\n        | \"feFlood\"\n        | \"feFuncA\"\n        | \"feFuncB\"\n        | \"feFuncG\"\n        | \"feFuncR\"\n        | \"feGaussianBlur\"\n        | \"feImage\"\n        | \"feMerge\"\n        | \"feMergeNode\"\n        | \"feMorphology\"\n        | \"feOffset\"\n        | \"fePointLight\"\n        | \"feSpecularLighting\"\n        | \"feSpotLight\"\n        | \"feTile\"\n        | \"feTurbulence\"\n        | \"foreignObject\"\n        | \"glyphRef\"\n        | \"linearGradient\"\n        | \"radialGradient\"\n        | \"textPath\" => true,\n        _ => !name.chars().any(|c| c.is_ascii_uppercase()),\n    }\n}\n\npub struct HtmlElement {\n    pub name: TagName,\n    pub props: ElementProps,\n    pub children: HtmlChildrenTree,\n}\n\nimpl PeekValue<()> for HtmlElement {\n    fn peek(cursor: Cursor) -> Option<()> {\n        HtmlElementOpen::peek(cursor)\n            .or_else(|| HtmlElementClose::peek(cursor))\n            .map(|_| ())\n    }\n}\n\nimpl Parse for HtmlElement {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        if HtmlElementClose::peek(input.cursor()).is_some() {\n            return match input.parse::<HtmlElementClose>() {\n                Ok(close) => Err(syn::Error::new_spanned(\n                    close.to_spanned(),\n                    \"this closing tag has no corresponding opening tag\",\n                )),\n                Err(err) => Err(err),\n            };\n        }\n\n        let open = input.parse::<HtmlElementOpen>()?;\n        // Return early if it's a self-closing tag\n        if open.is_self_closing() {\n            return Ok(HtmlElement {\n                name: open.name,\n                props: open.props,\n                children: HtmlChildrenTree::new(),\n            });\n        }\n\n        if let TagName::Lit(name) = &open.name {\n            // Void elements should not have children.\n            // See https://html.spec.whatwg.org/multipage/syntax.html#void-elements\n            //\n            // For dynamic tags this is done at runtime!\n            match name.to_ascii_lowercase_string().as_str() {\n                \"textarea\" => {\n                    return Err(syn::Error::new_spanned(\n                        open.to_spanned(),\n                        \"the tag `<textarea>` is a void element and cannot have children (hint: \\\n                         to provide value to it, rewrite it as `<textarea value={x} />`. If you \\\n                         wish to set the default value, rewrite it as `<textarea defaultvalue={x} \\\n                         />`)\",\n                    ))\n                }\n\n                \"area\" | \"base\" | \"br\" | \"col\" | \"embed\" | \"hr\" | \"img\" | \"input\" | \"link\"\n                | \"meta\" | \"param\" | \"source\" | \"track\" | \"wbr\" => {\n                    return Err(syn::Error::new_spanned(\n                        open.to_spanned(),\n                        format!(\n                            \"the tag `<{name}>` is a void element and cannot have children (hint: \\\n                             rewrite this as `<{name} />`)\",\n                        ),\n                    ))\n                }\n\n                _ => {}\n            }\n        }\n\n        let open_key = open.name.get_key();\n        let mut children = HtmlChildrenTree::new();\n        loop {\n            if input.is_empty() {\n                if is_ide_completion() {\n                    break;\n                }\n                return Err(syn::Error::new_spanned(\n                    open.to_spanned(),\n                    \"this opening tag has no corresponding closing tag\",\n                ));\n            }\n            if let Some(close_key) = HtmlElementClose::peek(input.cursor()) {\n                if open_key == close_key {\n                    break;\n                }\n            }\n\n            children.parse_child(input)?;\n        }\n\n        if !input.is_empty() || !is_ide_completion() {\n            input.parse::<HtmlElementClose>()?;\n        }\n\n        Ok(Self {\n            name: open.name,\n            props: open.props,\n            children,\n        })\n    }\n}\n\nimpl ToTokens for HtmlElement {\n    #[allow(clippy::cognitive_complexity)]\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Self {\n            name,\n            props,\n            children,\n        } = self;\n\n        let ElementProps {\n            classes,\n            attributes,\n            booleans,\n            value,\n            checked,\n            listeners,\n            special,\n            defaultvalue,\n        } = &props;\n\n        // attributes with special treatment\n\n        let node_ref = special.wrap_node_ref_attr();\n        let key = special.wrap_key_attr();\n        let value = || {\n            value\n                .as_ref()\n                .map(|prop| wrap_attr_value(prop.value.optimize_literals()))\n                .unwrap_or(quote! { ::std::option::Option::None })\n        };\n        let checked = || {\n            checked\n                .as_ref()\n                .map(|attr| {\n                    let value = &attr.value;\n                    quote! { ::std::option::Option::Some( #value ) }\n                })\n                .unwrap_or(quote! { ::std::option::Option::None })\n        };\n        let defaultvalue = || {\n            defaultvalue\n                .as_ref()\n                .map(|prop| wrap_attr_value(prop.value.optimize_literals()))\n                .unwrap_or(quote! { ::std::option::Option::None })\n        };\n\n        // other attributes\n\n        let attributes = {\n            let normal_attrs = attributes.iter().map(\n                |Prop {\n                     label,\n                     value,\n                     directive,\n                     ..\n                 }| {\n                    (\n                        label.to_lit_str(),\n                        value.optimize_literals_tagged(),\n                        *directive,\n                    )\n                },\n            );\n            let boolean_attrs = booleans.iter().filter_map(\n                |Prop {\n                     label,\n                     value,\n                     directive,\n                     ..\n                 }| {\n                    let key = label.to_lit_str();\n                    Some((\n                        key.clone(),\n                        match value {\n                            Expr::Lit(e) => match &e.lit {\n                                Lit::Bool(b) => Value::Static(if b.value {\n                                    quote! { #key }\n                                } else {\n                                    return None;\n                                }),\n                                _ => Value::Dynamic(quote_spanned! {value.span()=> {\n                                    ::yew::utils::__ensure_type::<::std::primitive::bool>(#value);\n                                    #key\n                                }}),\n                            },\n                            expr => Value::Dynamic(\n                                quote_spanned! {expr.span().resolved_at(Span::call_site())=>\n                                    if #expr {\n                                        ::std::option::Option::Some(\n                                            ::yew::virtual_dom::AttrValue::Static(#key)\n                                        )\n                                    } else {\n                                        ::std::option::Option::None\n                                    }\n                                },\n                            ),\n                        },\n                        *directive,\n                    ))\n                },\n            );\n\n            let class_attr =\n                classes\n                    .as_ref()\n                    .and_then(|classes| match classes.value.try_into_lit() {\n                        Some(lit) => {\n                            if lit.value().is_empty() {\n                                None\n                            } else {\n                                Some((\n                                    LitStr::new(\"class\", lit.span()),\n                                    Value::Static(quote! { #lit }),\n                                    None,\n                                ))\n                            }\n                        }\n                        None => {\n                            let expr = &classes.value;\n                            Some((\n                                LitStr::new(\"class\", classes.label.span()),\n                                Value::Dynamic(quote! {\n                                    ::std::convert::Into::<::yew::html::Classes>::into(#expr)\n                                }),\n                                None,\n                            ))\n                        }\n                    });\n\n            /// Try to turn attribute list into a `::yew::virtual_dom::Attributes::Static`\n            fn try_into_static(\n                src: &[(LitStr, Value, Option<PropDirective>)],\n            ) -> Option<TokenStream> {\n                if src\n                    .iter()\n                    .any(|(_, _, d)| matches!(d, Some(PropDirective::ApplyAsProperty(_))))\n                {\n                    // don't try to make a static attribute list if there are any properties to\n                    // assign\n                    return None;\n                }\n                let mut kv = Vec::with_capacity(src.len());\n                for (k, v, directive) in src.iter() {\n                    let v = match v {\n                        Value::Static(v) => quote! { #v },\n                        Value::Dynamic(_) => return None,\n                    };\n                    let v = match directive {\n                        Some(PropDirective::ApplyAsProperty(token)) => {\n                            quote_spanned!(token.span()=> ::yew::virtual_dom::AttributeOrProperty::Property(\n                                ::std::convert::Into::into(#v)\n                            ))\n                        }\n                        None => quote!(::yew::virtual_dom::AttributeOrProperty::Static(\n                            #v\n                        )),\n                    };\n                    kv.push(quote! { ( #k, #v) });\n                }\n\n                Some(quote! { ::yew::virtual_dom::Attributes::Static(&[#(#kv),*]) })\n            }\n\n            let attrs = normal_attrs\n                .chain(boolean_attrs)\n                .chain(class_attr)\n                .collect::<Vec<(LitStr, Value, Option<PropDirective>)>>();\n            try_into_static(&attrs).unwrap_or_else(|| {\n                let keys = attrs.iter().map(|(k, ..)| quote! { #k });\n                let values = attrs.iter().map(|(_, v, directive)| {\n                    let value = match directive {\n                        Some(PropDirective::ApplyAsProperty(token)) => {\n                            quote_spanned!(token.span()=> ::std::option::Option::Some(\n                                ::yew::virtual_dom::AttributeOrProperty::Property(\n                                    ::std::convert::Into::into(#v)\n                                ))\n                            )\n                        }\n                        None => {\n                            let value = wrap_attr_value(v);\n                            quote! {\n                                ::std::option::Option::map(#value, ::yew::virtual_dom::AttributeOrProperty::Attribute)\n                            }\n                        },\n                    };\n                    quote! { #value }\n                });\n                quote! {\n                    ::yew::virtual_dom::Attributes::Dynamic{\n                        keys: &[#(#keys),*],\n                        values: ::std::boxed::Box::new([#(#values),*]),\n                    }\n                }\n            })\n        };\n\n        let listeners = if listeners.is_empty() {\n            quote! { ::yew::virtual_dom::listeners::Listeners::None }\n        } else {\n            let listeners_it = listeners.iter().map(|Prop { label, value, .. }| {\n                let name = &label.name;\n                quote! {\n                    ::yew::html::#name::Wrapper::__macro_new(#value)\n                }\n            });\n\n            quote! {\n                ::yew::virtual_dom::listeners::Listeners::Pending(\n                    ::std::boxed::Box::new([#(#listeners_it),*])\n                )\n            }\n        };\n\n        // TODO: if none of the children have possibly None expressions or literals as keys, we can\n        // compute `VList.fully_keyed` at compile time.\n        let children = children.to_vnode_tokens();\n\n        tokens.extend(match &name {\n            TagName::Lit(dashedname) => {\n                let name_span = dashedname.span();\n                let name = dashedname.to_string();\n                let lowercase_name = dashedname.to_ascii_lowercase_string();\n                if !is_normalised_element_name(&dashedname.to_string()) {\n                    emit_warning!(\n                        name_span.clone(),\n                        format!(\n                            \"The tag '{dashedname}' is not matching its normalized form '{lowercase_name}' \\\n                             and is not a recognized SVG or MathML element. If you want to keep this name, \\\n                             you can use the dynamic tag `@{{\\\"{dashedname}\\\"}}` to silence this warning.\"\n                        )\n                    )\n                }\n                // Use lowercase for compile-time checks but preserve original casing in output\n                let node = match &*lowercase_name {\n                    \"input\" => {\n                        let value = value();\n                        let checked = checked();\n                        quote! {\n                            ::std::convert::Into::<::yew::virtual_dom::VNode>::into(\n                                ::yew::virtual_dom::VTag::__new_input(\n                                    #value,\n                                    #checked,\n                                    #node_ref,\n                                    #key,\n                                    #attributes,\n                                    #listeners,\n                                ),\n                            )\n                        }\n                    }\n                    \"textarea\" => {\n                        let value = value();\n                        let defaultvalue = defaultvalue();\n                        quote! {\n                            ::std::convert::Into::<::yew::virtual_dom::VNode>::into(\n                                ::yew::virtual_dom::VTag::__new_textarea(\n                                    #value,\n                                    #defaultvalue,\n                                    #node_ref,\n                                    #key,\n                                    #attributes,\n                                    #listeners,\n                                ),\n                            )\n                        }\n                    }\n                    _ => {\n                        quote! {\n                            ::std::convert::Into::<::yew::virtual_dom::VNode>::into(\n                                ::yew::virtual_dom::VTag::__new_other(\n                                    ::yew::virtual_dom::AttrValue::Static(#name),\n                                    #node_ref,\n                                    #key,\n                                    #attributes,\n                                    #listeners,\n                                    #children,\n                                ),\n                            )\n                        }\n                    }\n                };\n                // the return value can be inlined without the braces when this is stable:\n                // https://github.com/rust-lang/rust/issues/15701\n                quote_spanned!{\n                    name_span =>\n                    {\n                        #[allow(clippy::redundant_clone, unused_braces)]\n                        let node = #node;\n                        node\n                    }\n                }\n            }\n            TagName::Expr(name) => {\n                let vtag = Ident::new(\"__yew_vtag\", name.span());\n                let expr = name.expr.as_ref().map(Group::stream);\n                let vtag_name = Ident::new(\"__yew_vtag_name\", expr.span());\n\n                let void_children = Ident::new(\"__yew_void_children\", Span::mixed_site());\n\n                // handle special attribute value\n                let handle_value_attr = props.value.as_ref().map(|prop| {\n                    let v = prop.value.optimize_literals();\n                    quote_spanned! {v.span()=> {\n                        __yew_vtag.__macro_push_attr(\"value\", #v);\n                    }}\n                });\n\n                #[rustversion::since(1.88)]\n                fn derive_debug_tag(vtag: &Ident) -> String {\n                    let span = vtag.span().unwrap();\n                    // the file, line, column methods are stable since 1.88\n                    format!(\"[{}:{}:{}] \", span.file(), span.line(), span.column())\n                }\n                #[rustversion::before(1.88)]\n                fn derive_debug_tag(_: &Ident) -> &'static str {\n                    \"\"\n                }\n\n                let invalid_void_tag_msg_start = derive_debug_tag(&vtag);\n\n                let value = value();\n                let checked = checked();\n                let defaultvalue = defaultvalue();\n                // this way we get a nice error message (with the correct span) when the expression\n                // doesn't return a valid value\n                quote_spanned! {expr.span()=> {\n                    let mut #vtag_name = ::std::convert::Into::<\n                        ::yew::virtual_dom::AttrValue\n                    >::into(#expr);\n                    ::std::debug_assert!(\n                        #vtag_name.is_ascii(),\n                        \"a dynamic tag returned a tag name containing non ASCII characters: `{}`\",\n                        #vtag_name,\n                    );\n\n                    #[allow(clippy::redundant_clone, unused_braces, clippy::let_and_return)]\n                    let mut #vtag = match () {\n                        _ if \"input\".eq_ignore_ascii_case(::std::convert::AsRef::<::std::primitive::str>::as_ref(&#vtag_name)) => {\n                            ::yew::virtual_dom::VTag::__new_input(\n                                #value,\n                                #checked,\n                                #node_ref,\n                                #key,\n                                #attributes,\n                                #listeners,\n                            )\n                        }\n                        _ if \"textarea\".eq_ignore_ascii_case(::std::convert::AsRef::<::std::primitive::str>::as_ref(&#vtag_name)) => {\n                            ::yew::virtual_dom::VTag::__new_textarea(\n                                #value,\n                                #defaultvalue,\n                                #node_ref,\n                                #key,\n                                #attributes,\n                                #listeners,\n                            )\n                        }\n                        _ => {\n                            let mut __yew_vtag = ::yew::virtual_dom::VTag::__new_other(\n                                #vtag_name,\n                                #node_ref,\n                                #key,\n                                #attributes,\n                                #listeners,\n                                #children,\n                            );\n\n                            #handle_value_attr\n\n                            __yew_vtag\n                        }\n                    };\n\n                    // These are the runtime-checks exclusive to dynamic tags.\n                    // For literal tags this is already done at compile-time.\n                    //\n                    // check void element\n                    if ::yew::virtual_dom::VTag::children(&#vtag).is_some() &&\n                       !::std::matches!(\n                        ::yew::virtual_dom::VTag::children(&#vtag),\n                        ::std::option::Option::Some(::yew::virtual_dom::VNode::VList(ref #void_children)) if ::std::vec::Vec::is_empty(#void_children)\n                    ) {\n                        ::std::debug_assert!(\n                            !::std::matches!(#vtag.tag().to_ascii_lowercase().as_str(),\n                                \"area\" | \"base\" | \"br\" | \"col\" | \"embed\" | \"hr\" | \"img\" | \"input\"\n                                    | \"link\" | \"meta\" | \"param\" | \"source\" | \"track\" | \"wbr\" | \"textarea\"\n                            ),\n                            concat!(#invalid_void_tag_msg_start, \"a dynamic tag tried to create a `<{0}>` tag with children. `<{0}>` is a void element which can't have any children.\"),\n                            #vtag.tag(),\n                        );\n                    }\n\n                    ::std::convert::Into::<::yew::virtual_dom::VNode>::into(#vtag)\n                }}\n            }\n        });\n    }\n}\n\nfn wrap_attr_value<T: ToTokens>(value: T) -> TokenStream {\n    quote_spanned! {value.span()=>\n        ::yew::html::IntoPropValue::<\n            ::std::option::Option<\n                ::yew::virtual_dom::AttrValue\n            >\n        >\n        ::into_prop_value(#value)\n    }\n}\n\npub struct DynamicName {\n    at: Token![@],\n    expr: Option<Group>,\n}\n\nimpl Peek<'_, ()> for DynamicName {\n    fn peek(cursor: Cursor) -> Option<((), Cursor)> {\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '@' {\n            return None;\n        }\n\n        // move cursor past block if there is one\n        let cursor = cursor\n            .group(Delimiter::Brace)\n            .map(|(_, _, cursor)| cursor)\n            .unwrap_or(cursor);\n\n        Some(((), cursor))\n    }\n}\n\nimpl Parse for DynamicName {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let at = input.parse()?;\n        // the expression block is optional, closing tags don't have it.\n        let expr = input.parse().ok();\n        Ok(Self { at, expr })\n    }\n}\n\nimpl ToTokens for DynamicName {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Self { at, expr } = self;\n        tokens.extend(quote! {#at #expr});\n    }\n}\n\n#[derive(PartialEq)]\nenum TagKey {\n    Lit(HtmlDashedName),\n    Expr,\n}\n\npub enum TagName {\n    Lit(HtmlDashedName),\n    Expr(DynamicName),\n}\n\nimpl TagName {\n    fn get_key(&self) -> TagKey {\n        match self {\n            TagName::Lit(name) => TagKey::Lit(name.clone()),\n            TagName::Expr(_) => TagKey::Expr,\n        }\n    }\n}\n\nimpl Peek<'_, TagKey> for TagName {\n    fn peek(cursor: Cursor) -> Option<(TagKey, Cursor)> {\n        if let Some((_, cursor)) = DynamicName::peek(cursor) {\n            Some((TagKey::Expr, cursor))\n        } else {\n            HtmlDashedName::peek(cursor).map(|(name, cursor)| (TagKey::Lit(name), cursor))\n        }\n    }\n}\n\nimpl Parse for TagName {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        if DynamicName::peek(input.cursor()).is_some() {\n            DynamicName::parse(input).map(Self::Expr)\n        } else {\n            HtmlDashedName::parse(input).map(Self::Lit)\n        }\n    }\n}\n\nimpl ToTokens for TagName {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        match self {\n            TagName::Lit(name) => name.to_tokens(tokens),\n            TagName::Expr(name) => name.to_tokens(tokens),\n        }\n    }\n}\n\nstruct HtmlElementOpen {\n    tag: TagTokens,\n    name: TagName,\n    props: ElementProps,\n}\nimpl HtmlElementOpen {\n    fn is_self_closing(&self) -> bool {\n        self.tag.div.is_some()\n    }\n\n    fn to_spanned(&self) -> impl ToTokens {\n        self.tag.to_spanned()\n    }\n}\n\nimpl PeekValue<TagKey> for HtmlElementOpen {\n    fn peek(cursor: Cursor) -> Option<TagKey> {\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '<' {\n            return None;\n        }\n\n        let (tag_key, cursor) = TagName::peek(cursor)?;\n        if let TagKey::Lit(name) = &tag_key {\n            // Avoid parsing `<key=[...]>` as an element. It needs to be parsed as an `HtmlList`.\n            if name.to_string() == \"key\" {\n                let (punct, _) = cursor.punct()?;\n                // ... unless it isn't followed by a '='. `<key></key>` is a valid element!\n                if punct.as_char() == '=' {\n                    return None;\n                }\n            } else if !non_capitalized_ascii(&name.to_string()) {\n                return None;\n            }\n        }\n\n        Some(tag_key)\n    }\n}\n\nimpl Parse for HtmlElementOpen {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        TagTokens::parse_start_content(input, |input, tag| {\n            let name = input.parse::<TagName>()?;\n            let mut props = input.parse::<ElementProps>()?;\n\n            match &name {\n                TagName::Lit(name) => {\n                    // Don't treat value as special for non input / textarea fields\n                    // For dynamic tags this is done at runtime!\n                    match name.to_ascii_lowercase_string().as_str() {\n                        \"input\" | \"textarea\" => {}\n                        _ => {\n                            if let Some(attr) = props.value.take() {\n                                props.attributes.push(attr);\n                            }\n                            if let Some(attr) = props.checked.take() {\n                                props.attributes.push(attr);\n                            }\n                        }\n                    }\n                }\n                TagName::Expr(name) => {\n                    if name.expr.is_none() {\n                        return Err(syn::Error::new_spanned(\n                            name,\n                            \"this dynamic tag is missing an expression block defining its value\",\n                        ));\n                    }\n                }\n            }\n\n            Ok(Self { tag, name, props })\n        })\n    }\n}\n\nstruct HtmlElementClose {\n    tag: TagTokens,\n    _name: TagName,\n}\nimpl HtmlElementClose {\n    fn to_spanned(&self) -> impl ToTokens {\n        self.tag.to_spanned()\n    }\n}\n\nimpl PeekValue<TagKey> for HtmlElementClose {\n    fn peek(cursor: Cursor) -> Option<TagKey> {\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '<' {\n            return None;\n        }\n\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '/' {\n            return None;\n        }\n\n        let (tag_key, cursor) = TagName::peek(cursor)?;\n        if matches!(&tag_key, TagKey::Lit(name) if !non_capitalized_ascii(&name.to_string())) {\n            return None;\n        }\n\n        let (punct, _) = cursor.punct()?;\n        (punct.as_char() == '>').then_some(tag_key)\n    }\n}\n\nimpl Parse for HtmlElementClose {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        TagTokens::parse_end_content(input, |input, tag| {\n            let name = input.parse()?;\n\n            if let TagName::Expr(name) = &name {\n                if let Some(expr) = &name.expr {\n                    return Err(syn::Error::new_spanned(\n                        expr,\n                        \"dynamic closing tags must not have a body (hint: replace it with just \\\n                         `</@>`)\",\n                    ));\n                }\n            }\n\n            Ok(Self { tag, _name: name })\n        })\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_for.rs",
    "content": "use proc_macro2::{Ident, TokenStream};\nuse quote::{quote, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::token::{For, In};\nuse syn::{braced, Expr, Pat};\n\nuse super::{HtmlChildrenTree, ToNodeIterator};\nuse crate::html_tree::HtmlTree;\nuse crate::PeekValue;\n\n/// Determines if an expression is guaranteed to always return the same value anywhere.\nfn is_contextless_pure(expr: &Expr) -> bool {\n    match expr {\n        Expr::Lit(_) => true,\n        Expr::Path(path) => path.path.get_ident().is_none(),\n        _ => false,\n    }\n}\n\npub struct HtmlFor {\n    pat: Pat,\n    iter: Expr,\n    body: HtmlChildrenTree,\n}\n\nimpl PeekValue<()> for HtmlFor {\n    fn peek(cursor: Cursor) -> Option<()> {\n        let (ident, _) = cursor.ident()?;\n        (ident == \"for\").then_some(())\n    }\n}\n\nimpl Parse for HtmlFor {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        For::parse(input)?;\n        let pat = Pat::parse_single(input)?;\n        In::parse(input)?;\n        let iter = Expr::parse_without_eager_brace(input)?;\n\n        let body_stream;\n        braced!(body_stream in input);\n\n        let body = HtmlChildrenTree::parse_delimited(&body_stream)?;\n        // TODO: more concise code by using if-let guards once MSRV is raised\n        for child in body.0.iter() {\n            let HtmlTree::Element(element) = child else {\n                continue;\n            };\n\n            let Some(key) = &element.props.special.key else {\n                continue;\n            };\n\n            if is_contextless_pure(&key.value) {\n                return Err(syn::Error::new(\n                    key.value.span(),\n                    \"duplicate key for a node in a `for`-loop\\nthis will create elements with \\\n                     duplicate keys if the loop iterates more than once\",\n                ));\n            }\n        }\n        Ok(Self { pat, iter, body })\n    }\n}\n\nimpl ToTokens for HtmlFor {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Self { pat, iter, body } = self;\n        let acc = Ident::new(\"__yew_v\", iter.span());\n\n        let alloc_opt = body\n            .size_hint()\n            .filter(|&size| size > 1) // explicitly reserving space for 1 more element is redundant\n            .map(|size| quote!( #acc.reserve(#size) ));\n\n        let vlist_gen = match body.fully_keyed() {\n            Some(true) => quote! {\n                ::yew::virtual_dom::VList::__macro_new(\n                    #acc,\n                    ::std::option::Option::None,\n                    ::yew::virtual_dom::FullyKeyedState::KnownFullyKeyed\n                )\n            },\n            Some(false) => quote! {\n                ::yew::virtual_dom::VList::__macro_new(\n                    #acc,\n                    ::std::option::Option::None,\n                    ::yew::virtual_dom::FullyKeyedState::KnownMissingKeys\n                )\n            },\n            None => quote! {\n                ::yew::virtual_dom::VList::with_children(#acc, ::std::option::Option::None)\n            },\n        };\n\n        let body = body.0.iter().map(|child| {\n            if let Some(child) = child.to_node_iterator_stream() {\n                quote!( #acc.extend(#child) )\n            } else {\n                quote!( #acc.push(::std::convert::Into::into(#child)) )\n            }\n        });\n\n        tokens.extend(quote!({\n            let mut #acc = ::std::vec::Vec::<::yew::virtual_dom::VNode>::new();\n            ::std::iter::Iterator::for_each(\n                ::std::iter::IntoIterator::into_iter(#iter),\n                |#pat| { #alloc_opt; #(#body);* }\n            );\n            #vlist_gen\n        }))\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_if.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::{quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{parse_quote, Expr, Token};\n\nuse super::HtmlRootBraced;\nuse crate::PeekValue;\n\npub struct HtmlIf {\n    if_token: Token![if],\n    cond: Box<Expr>,\n    then_branch: HtmlRootBraced,\n    else_branch: Option<(Token![else], Box<HtmlRootBracedOrIf>)>,\n}\n\nimpl PeekValue<()> for HtmlIf {\n    fn peek(cursor: Cursor) -> Option<()> {\n        let (ident, _) = cursor.ident()?;\n        (ident == \"if\").then_some(())\n    }\n}\n\nimpl Parse for HtmlIf {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let if_token = input.parse()?;\n        let cond = Box::new(input.call(Expr::parse_without_eager_brace)?);\n        match &*cond {\n            Expr::Block(syn::ExprBlock { block, .. }) if block.stmts.is_empty() => {\n                return Err(syn::Error::new(\n                    cond.span(),\n                    \"missing condition for `if` expression\",\n                ))\n            }\n            _ => {}\n        }\n        if input.is_empty() {\n            return Err(syn::Error::new(\n                cond.span(),\n                \"this `if` expression has a condition, but no block\",\n            ));\n        }\n\n        let then_branch = input.parse()?;\n        let else_branch = input\n            .parse::<Token![else]>()\n            .ok()\n            .map(|else_token| {\n                if input.is_empty() {\n                    return Err(syn::Error::new(\n                        else_token.span(),\n                        \"expected block or `if` after `else`\",\n                    ));\n                }\n\n                input.parse().map(|branch| (else_token, branch))\n            })\n            .transpose()?;\n\n        Ok(HtmlIf {\n            if_token,\n            cond,\n            then_branch,\n            else_branch,\n        })\n    }\n}\n\nimpl ToTokens for HtmlIf {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Self {\n            if_token,\n            cond,\n            then_branch,\n            else_branch,\n        } = self;\n        let default_else_branch = parse_quote! { {} };\n        let else_branch = else_branch\n            .as_ref()\n            .map(|(_, branch)| branch)\n            .unwrap_or(&default_else_branch);\n        let new_tokens = quote_spanned! {if_token.span()=>\n            if #cond #then_branch else #else_branch\n        };\n\n        tokens.extend(new_tokens);\n    }\n}\n\npub enum HtmlRootBracedOrIf {\n    Branch(HtmlRootBraced),\n    If(HtmlIf),\n}\n\nimpl PeekValue<()> for HtmlRootBracedOrIf {\n    fn peek(cursor: Cursor) -> Option<()> {\n        HtmlRootBraced::peek(cursor).or_else(|| HtmlIf::peek(cursor))\n    }\n}\n\nimpl Parse for HtmlRootBracedOrIf {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        if HtmlRootBraced::peek(input.cursor()).is_some() {\n            input.parse().map(Self::Branch)\n        } else {\n            input.parse().map(Self::If)\n        }\n    }\n}\n\nimpl ToTokens for HtmlRootBracedOrIf {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        match self {\n            Self::Branch(x) => x.to_tokens(tokens),\n            Self::If(x) => x.to_tokens(tokens),\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_iterable.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::{quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{Expr, Token};\n\nuse super::ToNodeIterator;\nuse crate::PeekValue;\n\npub struct HtmlIterable(Expr);\n\nimpl PeekValue<()> for HtmlIterable {\n    fn peek(cursor: Cursor) -> Option<()> {\n        let (ident, _) = cursor.ident()?;\n        (ident == \"for\").then_some(())\n    }\n}\n\nimpl Parse for HtmlIterable {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let for_token = input.parse::<Token![for]>()?;\n\n        match input.parse() {\n            Ok(expr) => Ok(HtmlIterable(expr)),\n            Err(err) => {\n                if err.to_string().starts_with(\"unexpected end of input\") {\n                    Err(syn::Error::new_spanned(\n                        for_token,\n                        \"expected an expression after the keyword `for`\",\n                    ))\n                } else {\n                    Err(err)\n                }\n            }\n        }\n    }\n}\n\nimpl ToTokens for HtmlIterable {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let expr = &self.0;\n        let new_tokens = quote_spanned! {expr.span()=>\n            #[allow(unused_braces)]\n            ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(::std::iter::IntoIterator::into_iter(#expr))\n        };\n\n        tokens.extend(new_tokens);\n    }\n}\n\nimpl ToNodeIterator for HtmlIterable {\n    fn to_node_iterator_stream(&self) -> Option<TokenStream> {\n        let Self(expr) = self;\n        // #expr can return anything that implements IntoIterator<Item=Into<T>>\n        // We use a util method to avoid clippy warnings and reduce generated code size\n        Some(quote_spanned! {expr.span()=>\n            ::yew::utils::into_node_iter(#expr)\n        })\n    }\n\n    fn is_singular(&self) -> bool {\n        false\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_list.rs",
    "content": "use quote::{quote, quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::Expr;\n\nuse super::html_dashed_name::HtmlDashedName;\nuse super::{HtmlChildrenTree, TagTokens};\nuse crate::props::Prop;\nuse crate::{Peek, PeekValue};\n\npub struct HtmlList {\n    pub open: HtmlListOpen,\n    pub children: HtmlChildrenTree,\n    close: HtmlListClose,\n}\n\nimpl PeekValue<()> for HtmlList {\n    fn peek(cursor: Cursor) -> Option<()> {\n        HtmlListOpen::peek(cursor)\n            .or_else(|| HtmlListClose::peek(cursor))\n            .map(|_| ())\n    }\n}\n\nimpl Parse for HtmlList {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        if HtmlListClose::peek(input.cursor()).is_some() {\n            return match input.parse::<HtmlListClose>() {\n                Ok(close) => Err(syn::Error::new_spanned(\n                    close.to_spanned(),\n                    \"this closing fragment has no corresponding opening fragment\",\n                )),\n                Err(err) => Err(err),\n            };\n        }\n\n        let open = input.parse::<HtmlListOpen>()?;\n        let mut children = HtmlChildrenTree::new();\n        while HtmlListClose::peek(input.cursor()).is_none() {\n            children.parse_child(input)?;\n            if input.is_empty() {\n                return Err(syn::Error::new_spanned(\n                    open.to_spanned(),\n                    \"this opening fragment has no corresponding closing fragment\",\n                ));\n            }\n        }\n\n        let close = input.parse::<HtmlListClose>()?;\n\n        Ok(Self {\n            open,\n            children,\n            close,\n        })\n    }\n}\n\nimpl ToTokens for HtmlList {\n    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {\n        let Self {\n            open,\n            children,\n            close,\n        } = &self;\n\n        let key = if let Some(key) = &open.props.key {\n            quote_spanned! {key.span()=> ::std::option::Option::Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#key))}\n        } else {\n            quote! { ::std::option::Option::None }\n        };\n\n        let span = {\n            let open = open.to_spanned();\n            let close = close.to_spanned();\n            quote! { #open #close }\n        }\n        .span();\n\n        tokens.extend(match children.fully_keyed() {\n            Some(true) => quote_spanned!{span=>\n                ::yew::virtual_dom::VList::__macro_new(#children, #key, ::yew::virtual_dom::FullyKeyedState::KnownFullyKeyed)\n            },\n            Some(false) => quote_spanned!{span=>\n                ::yew::virtual_dom::VList::__macro_new(#children, #key, ::yew::virtual_dom::FullyKeyedState::KnownMissingKeys)\n            },\n            None => quote_spanned!{span=>\n                ::yew::virtual_dom::VList::with_children(#children, #key)\n            }\n        });\n    }\n}\n\npub struct HtmlListOpen {\n    tag: TagTokens,\n    pub props: HtmlListProps,\n}\nimpl HtmlListOpen {\n    fn to_spanned(&self) -> impl ToTokens {\n        self.tag.to_spanned()\n    }\n}\n\nimpl PeekValue<()> for HtmlListOpen {\n    fn peek(cursor: Cursor) -> Option<()> {\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '<' {\n            return None;\n        }\n        // make sure it's either a property (key=value) or it's immediately closed\n        if let Some((_, cursor)) = HtmlDashedName::peek(cursor) {\n            let (punct, _) = cursor.punct()?;\n            (punct.as_char() == '=' || punct.as_char() == '?').then_some(())\n        } else {\n            let (punct, _) = cursor.punct()?;\n            (punct.as_char() == '>').then_some(())\n        }\n    }\n}\n\nimpl Parse for HtmlListOpen {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        TagTokens::parse_start_content(input, |input, tag| {\n            let props = input.parse()?;\n            Ok(Self { tag, props })\n        })\n    }\n}\n\npub struct HtmlListProps {\n    pub key: Option<Expr>,\n}\nimpl Parse for HtmlListProps {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let key = if input.is_empty() {\n            None\n        } else {\n            let prop: Prop = input.parse()?;\n            if !input.is_empty() {\n                return Err(input.error(\"only a single `key` prop is allowed on a fragment\"));\n            }\n\n            if prop.label.to_ascii_lowercase_string() != \"key\" {\n                return Err(syn::Error::new_spanned(\n                    prop.label,\n                    \"fragments only accept the `key` prop\",\n                ));\n            }\n\n            Some(prop.value)\n        };\n\n        Ok(Self { key })\n    }\n}\n\nstruct HtmlListClose(TagTokens);\nimpl HtmlListClose {\n    fn to_spanned(&self) -> impl ToTokens {\n        self.0.to_spanned()\n    }\n}\nimpl PeekValue<()> for HtmlListClose {\n    fn peek(cursor: Cursor) -> Option<()> {\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '<' {\n            return None;\n        }\n        let (punct, cursor) = cursor.punct()?;\n        if punct.as_char() != '/' {\n            return None;\n        }\n\n        let (punct, _) = cursor.punct()?;\n        (punct.as_char() == '>').then_some(())\n    }\n}\nimpl Parse for HtmlListClose {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        TagTokens::parse_end_content(input, |input, tag| {\n            if !input.is_empty() {\n                Err(input.error(\"unexpected content in list close\"))\n            } else {\n                Ok(Self(tag))\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/html_node.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::parse::{Parse, ParseStream, Result};\nuse syn::spanned::Spanned;\nuse syn::Lit;\n\nuse super::ToNodeIterator;\nuse crate::stringify::Stringify;\nuse crate::PeekValue;\n\npub enum HtmlNode {\n    Literal(Box<Lit>),\n    Expression(Box<TokenStream>),\n}\n\nimpl Parse for HtmlNode {\n    fn parse(input: ParseStream) -> Result<Self> {\n        let node = if HtmlNode::peek(input.cursor()).is_some() {\n            let lit = input.parse()?;\n            match lit {\n                Lit::ByteStr(lit) => {\n                    return Err(syn::Error::new(\n                        lit.span(),\n                        \"byte-strings can't be converted to HTML text\n                         note: remove the `b` prefix or convert this to a `String`\",\n                    ))\n                }\n                Lit::Verbatim(lit) => {\n                    return Err(syn::Error::new(lit.span(), \"unsupported literal\"))\n                }\n                _ => (),\n            }\n            HtmlNode::Literal(Box::new(lit))\n        } else {\n            HtmlNode::Expression(Box::new(input.parse()?))\n        };\n\n        Ok(node)\n    }\n}\n\nimpl PeekValue<()> for HtmlNode {\n    fn peek(cursor: Cursor) -> Option<()> {\n        cursor.literal().map(|_| ()).or_else(|| {\n            let (ident, _) = cursor.ident()?;\n            match ident.to_string().as_str() {\n                \"true\" | \"false\" => Some(()),\n                _ => None,\n            }\n        })\n    }\n}\n\nimpl ToTokens for HtmlNode {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        tokens.extend(match &self {\n            HtmlNode::Literal(lit) => {\n                let sr = lit.stringify();\n                quote_spanned! {lit.span()=> ::yew::virtual_dom::VText::new(#sr) }\n            }\n            HtmlNode::Expression(expr) => quote! {#expr},\n        });\n    }\n}\n\nimpl ToNodeIterator for HtmlNode {\n    fn to_node_iterator_stream(&self) -> Option<TokenStream> {\n        match self {\n            Self::Literal(_) => None,\n            Self::Expression(expr) => {\n                // NodeSeq turns both Into<T> and Vec<Into<T>> into IntoIterator<Item = T>\n                Some(quote_spanned! {expr.span().resolved_at(Span::call_site())=>\n                    ::std::convert::Into::<::yew::utils::NodeSeq<_, _>>::into(#expr)\n                })\n            }\n        }\n    }\n\n    fn is_singular(&self) -> bool {\n        match self {\n            Self::Literal(_) => true,\n            Self::Expression(_) => false,\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/lint/mod.rs",
    "content": "//! Lints to catch possible misuse of the `html!` macro use. At the moment these are mostly focused\n//! on accessibility.\n\nuse proc_macro_error::emit_warning;\nuse syn::spanned::Spanned;\n\nuse super::html_element::{HtmlElement, TagName};\nuse super::HtmlTree;\nuse crate::props::{ElementProps, Prop};\n\n/// Lints HTML elements to check if they are well formed. If the element is not well-formed, then\n/// use `proc-macro-error` (and the `emit_warning!` macro) to produce a warning. At present, these\n/// are only emitted on nightly.\npub trait Lint {\n    #[cfg_attr(not(yew_lints), allow(dead_code))]\n    fn lint(element: &HtmlElement);\n}\n\n/// Applies all the lints to the HTML tree.\npub fn lint_all(tree: &HtmlTree) {\n    lint::<AHrefLint>(tree);\n    lint::<ImgAltLint>(tree);\n}\n\n/// Applies a specific lint to the HTML tree.\npub fn lint<L>(tree: &HtmlTree)\nwhere\n    L: Lint,\n{\n    let _ = L::lint;\n    #[cfg(not(yew_lints))]\n    let _ = tree;\n    #[cfg(yew_lints)]\n    match tree {\n        HtmlTree::List(list) => {\n            for child in &list.children.0 {\n                lint::<L>(child)\n            }\n        }\n        HtmlTree::Element(el) => L::lint(el),\n        _ => {}\n    }\n}\n\n/// Retrieves an attribute from an element and returns a reference valid for the lifetime of the\n/// element (if that attribute can be found on the prop).\n///\n/// Attribute names are lowercased before being compared (so pass \"href\" for `name` and not \"HREF\").\nfn get_attribute<'a>(props: &'a ElementProps, name: &str) -> Option<&'a Prop> {\n    props\n        .attributes\n        .iter()\n        .find(|item| item.label.eq_ignore_ascii_case(name))\n}\n\n/// Lints to check if anchor (`<a>`) tags have valid `href` attributes defined.\npub struct AHrefLint;\n\nimpl Lint for AHrefLint {\n    fn lint(element: &HtmlElement) {\n        if let TagName::Lit(ref tag_name) = element.name {\n            if !tag_name.eq_ignore_ascii_case(\"a\") {\n                return;\n            };\n            if let Some(prop) = get_attribute(&element.props, \"href\") {\n                if let syn::Expr::Lit(lit) = &prop.value {\n                    if let syn::Lit::Str(href) = &lit.lit {\n                        let href_value = href.value();\n                        match href_value.as_ref() {\n                            \"#\" | \"javascript:void(0)\" => emit_warning!(\n                                lit.span(),\n                                format!(\"'{href_value}' is not a suitable value for the `href` attribute. \\\n                                        Without a meaningful attribute assistive technologies \\\n                                        will struggle to understand your webpage. \\\n                                        https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML#onclick_events\"\n                            )),\n                            _ => {}\n\n                        }\n                    }\n                };\n            } else {\n                emit_warning!(\n                    quote::quote! {#tag_name}.span(),\n                    \"All `<a>` elements should have a `href` attribute. This makes it possible \\\n                        for assistive technologies to correctly interpret what your links point to. \\\n                        https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML#more_on_links\"\n                )\n            }\n        }\n    }\n}\n\n/// Checks to make sure that images have `alt` attributes defined.\npub struct ImgAltLint;\n\nimpl Lint for ImgAltLint {\n    fn lint(element: &HtmlElement) {\n        if let super::html_element::TagName::Lit(ref tag_name) = element.name {\n            if !tag_name.eq_ignore_ascii_case(\"img\") {\n                return;\n            };\n            if get_attribute(&element.props, \"alt\").is_none() {\n                emit_warning!(\n                    quote::quote! {#tag_name}.span(),\n                    \"All `<img>` tags should have an `alt` attribute which provides a \\\n                     human-readable description \"\n                )\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/mod.rs",
    "content": "use proc_macro2::{Delimiter, Ident, Span, TokenStream};\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::buffer::Cursor;\nuse syn::ext::IdentExt;\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::{braced, token, Token};\n\nuse crate::{is_ide_completion, PeekValue};\n\nmod html_block;\nmod html_component;\nmod html_dashed_name;\nmod html_element;\nmod html_for;\nmod html_if;\nmod html_iterable;\nmod html_list;\nmod html_node;\nmod lint;\nmod tag;\n\nuse html_block::HtmlBlock;\nuse html_component::HtmlComponent;\npub use html_dashed_name::HtmlDashedName;\nuse html_element::HtmlElement;\nuse html_if::HtmlIf;\nuse html_iterable::HtmlIterable;\nuse html_list::HtmlList;\nuse html_node::HtmlNode;\nuse tag::TagTokens;\n\nuse self::html_block::BlockContent;\nuse self::html_for::HtmlFor;\n\npub enum HtmlType {\n    Block,\n    Component,\n    List,\n    Element,\n    If,\n    For,\n    Empty,\n}\n\npub enum HtmlTree {\n    Block(Box<HtmlBlock>),\n    Component(Box<HtmlComponent>),\n    List(Box<HtmlList>),\n    Element(Box<HtmlElement>),\n    If(Box<HtmlIf>),\n    For(Box<HtmlFor>),\n    Empty,\n}\n\nimpl Parse for HtmlTree {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let html_type = Self::peek_html_type(input)\n            .ok_or_else(|| input.error(\"expected a valid html element\"))?;\n        Ok(match html_type {\n            HtmlType::Empty => Self::Empty,\n            HtmlType::Component => Self::Component(Box::new(input.parse()?)),\n            HtmlType::Element => Self::Element(Box::new(input.parse()?)),\n            HtmlType::Block => Self::Block(Box::new(input.parse()?)),\n            HtmlType::List => Self::List(Box::new(input.parse()?)),\n            HtmlType::If => Self::If(Box::new(input.parse()?)),\n            HtmlType::For => Self::For(Box::new(input.parse()?)),\n        })\n    }\n}\n\nimpl HtmlTree {\n    /// Determine the [`HtmlType`] before actually parsing it.\n    /// Even though this method accepts a [`ParseStream`], it is forked and the original stream is\n    /// not modified. Once a certain `HtmlType` can be deduced for certain, the function eagerly\n    /// returns with the appropriate type. If invalid html tag, returns `None`.\n    fn peek_html_type(input: ParseStream) -> Option<HtmlType> {\n        let input = input.fork(); // do not modify original ParseStream\n        let cursor = input.cursor();\n\n        if input.is_empty() {\n            Some(HtmlType::Empty)\n        } else if HtmlBlock::peek(cursor).is_some() {\n            Some(HtmlType::Block)\n        } else if HtmlIf::peek(cursor).is_some() {\n            Some(HtmlType::If)\n        } else if HtmlFor::peek(cursor).is_some() {\n            Some(HtmlType::For)\n        } else if input.peek(Token![<]) {\n            let _lt: Token![<] = input.parse().ok()?;\n\n            // eat '/' character for unmatched closing tag\n            let _slash: Option<Token![/]> = input.parse().ok();\n\n            if input.peek(Token![>]) {\n                Some(HtmlType::List)\n            } else if input.peek(Token![@]) {\n                Some(HtmlType::Element) // dynamic element\n            } else if input.peek(Token![::]) {\n                Some(HtmlType::Component)\n            } else if input.peek(Ident::peek_any) {\n                let ident = Ident::parse_any(&input).ok()?;\n                let ident_str = ident.to_string();\n\n                if input.peek(Token![=]) || (input.peek(Token![?]) && input.peek2(Token![=])) {\n                    Some(HtmlType::List)\n                } else if ident_str.chars().next().unwrap().is_ascii_uppercase()\n                    || input.peek(Token![::])\n                    || is_ide_completion() && ident_str.chars().any(|c| c.is_ascii_uppercase())\n                {\n                    Some(HtmlType::Component)\n                } else {\n                    Some(HtmlType::Element)\n                }\n            } else {\n                None\n            }\n        } else {\n            None\n        }\n    }\n}\n\nimpl ToTokens for HtmlTree {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        lint::lint_all(self);\n        match self {\n            Self::Empty => tokens.extend(quote! {\n                <::yew::virtual_dom::VNode as ::std::default::Default>::default()\n            }),\n            Self::Component(comp) => comp.to_tokens(tokens),\n            Self::Element(tag) => tag.to_tokens(tokens),\n            Self::List(list) => list.to_tokens(tokens),\n            Self::Block(block) => block.to_tokens(tokens),\n            Self::If(block) => block.to_tokens(tokens),\n            Self::For(block) => block.to_tokens(tokens),\n        }\n    }\n}\n\npub enum HtmlRoot {\n    Tree(HtmlTree),\n    Node(Box<HtmlNode>),\n}\n\nimpl Parse for HtmlRoot {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let html_root = if HtmlTree::peek_html_type(input).is_some() {\n            Self::Tree(input.parse()?)\n        } else {\n            Self::Node(Box::new(input.parse()?))\n        };\n\n        if !input.is_empty() {\n            let stream: TokenStream = input.parse()?;\n            Err(syn::Error::new_spanned(\n                stream,\n                \"only one root html element is allowed (hint: you can wrap multiple html elements \\\n                 in a fragment `<></>`)\",\n            ))\n        } else {\n            Ok(html_root)\n        }\n    }\n}\n\nimpl ToTokens for HtmlRoot {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        match self {\n            Self::Tree(tree) => tree.to_tokens(tokens),\n            Self::Node(node) => node.to_tokens(tokens),\n        }\n    }\n}\n\n/// Same as HtmlRoot but always returns a VNode.\npub struct HtmlRootVNode(HtmlRoot);\nimpl Parse for HtmlRootVNode {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        input.parse().map(Self)\n    }\n}\n\nimpl ToTokens for HtmlRootVNode {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let new_tokens = self.0.to_token_stream();\n        tokens.extend(\n            quote_spanned! {self.0.span().resolved_at(Span::mixed_site())=> {\n                #[allow(clippy::useless_conversion)]\n                <::yew::virtual_dom::VNode as ::std::convert::From<_>>::from(#new_tokens)\n            }},\n        );\n    }\n}\n\n/// This trait represents a type that can be unfolded into multiple html nodes.\npub trait ToNodeIterator {\n    /// Generate a token stream which produces a value that implements IntoIterator<Item=T> where T\n    /// is inferred by the compiler. The easiest way to achieve this is to call `.into()` on\n    /// each element. If the resulting iterator only ever yields a single item this function\n    /// should return None instead.\n    fn to_node_iterator_stream(&self) -> Option<TokenStream>;\n    /// Returns a boolean indicating whether the node can only ever unfold into 1 node\n    /// Same as calling `.to_node_iterator_stream().is_none()`,\n    /// but doesn't actually construct any token stream\n    fn is_singular(&self) -> bool;\n}\n\nimpl ToNodeIterator for HtmlTree {\n    fn to_node_iterator_stream(&self) -> Option<TokenStream> {\n        match self {\n            Self::Block(block) => block.to_node_iterator_stream(),\n            // everything else is just a single node.\n            _ => None,\n        }\n    }\n\n    fn is_singular(&self) -> bool {\n        match self {\n            Self::Block(block) => block.is_singular(),\n            _ => true,\n        }\n    }\n}\n\npub struct HtmlChildrenTree(pub Vec<HtmlTree>);\n\nimpl HtmlChildrenTree {\n    pub fn new() -> Self {\n        Self(Vec::new())\n    }\n\n    pub fn parse_child(&mut self, input: ParseStream) -> syn::Result<()> {\n        self.0.push(input.parse()?);\n        Ok(())\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n\n    // Check if each child represents a single node.\n    // This is the case when no expressions are used.\n    fn only_single_node_children(&self) -> bool {\n        self.0.iter().all(HtmlTree::is_singular)\n    }\n\n    pub fn to_build_vec_token_stream(&self) -> TokenStream {\n        let Self(children) = self;\n\n        if self.only_single_node_children() {\n            // optimize for the common case where all children are single nodes (only using literal\n            // html).\n            let children_into = children\n                .iter()\n                .map(|child| quote_spanned! {child.span()=> ::std::convert::Into::into(#child) });\n            return quote! {\n                [#(#children_into),*].to_vec()\n            };\n        }\n\n        let vec_ident = Ident::new(\"__yew_v\", Span::mixed_site());\n        let add_children_streams = children.iter().map(|child| {\n            if let Some(node_iterator_stream) = child.to_node_iterator_stream() {\n                quote! {\n                    ::std::iter::Extend::extend(&mut #vec_ident, #node_iterator_stream);\n                }\n            } else {\n                quote_spanned! {child.span()=>\n                    #vec_ident.push(::std::convert::Into::into(#child));\n                }\n            }\n        });\n\n        quote! {\n            {\n                let mut #vec_ident = ::std::vec::Vec::new();\n                #(#add_children_streams)*\n                #vec_ident\n            }\n        }\n    }\n\n    fn parse_delimited(input: ParseStream) -> syn::Result<Self> {\n        let mut children = HtmlChildrenTree::new();\n\n        while !input.is_empty() {\n            children.parse_child(input)?;\n        }\n\n        Ok(children)\n    }\n\n    pub fn to_children_renderer_tokens(&self) -> Option<TokenStream> {\n        match self.0[..] {\n            [] => None,\n            [HtmlTree::Component(ref children)] => Some(quote! { #children }),\n            [HtmlTree::Element(ref children)] => Some(quote! { #children }),\n            [HtmlTree::Block(ref m)] => {\n                // We only want to process `{vnode}` and not `{for vnodes}`.\n                // This should be converted into a if let guard once https://github.com/rust-lang/rust/issues/51114 is stable.\n                // Or further nested once deref pattern (https://github.com/rust-lang/rust/issues/87121) is stable.\n                if let HtmlBlock {\n                    content: BlockContent::Node(children),\n                    ..\n                } = m.as_ref()\n                {\n                    Some(quote! { #children })\n                } else {\n                    Some(quote! { ::yew::html::ChildrenRenderer::new(#self) })\n                }\n            }\n            _ => Some(quote! { ::yew::html::ChildrenRenderer::new(#self) }),\n        }\n    }\n\n    pub fn to_vnode_tokens(&self) -> TokenStream {\n        match self.0[..] {\n            [] => quote! {::std::default::Default::default() },\n            [HtmlTree::Component(ref children)] => {\n                quote! { ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(#children) }\n            }\n            [HtmlTree::Element(ref children)] => {\n                quote! { ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(#children) }\n            }\n            [HtmlTree::Block(ref m)] => {\n                // We only want to process `{vnode}` and not `{for vnodes}`.\n                // This should be converted into a if let guard once https://github.com/rust-lang/rust/issues/51114 is stable.\n                // Or further nested once deref pattern (https://github.com/rust-lang/rust/issues/87121) is stable.\n                if let HtmlBlock {\n                    content: BlockContent::Node(children),\n                    ..\n                } = m.as_ref()\n                {\n                    quote! { ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(#children) }\n                } else {\n                    quote! {\n                        ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(\n                            ::yew::html::ChildrenRenderer::new(#self)\n                        )\n                    }\n                }\n            }\n            _ => quote! {\n                ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(\n                    ::yew::html::ChildrenRenderer::new(#self)\n                )\n            },\n        }\n    }\n\n    pub fn size_hint(&self) -> Option<usize> {\n        self.only_single_node_children().then_some(self.0.len())\n    }\n\n    pub fn fully_keyed(&self) -> Option<bool> {\n        for child in self.0.iter() {\n            match child {\n                HtmlTree::Block(block) => {\n                    return if let BlockContent::Node(node) = &block.content {\n                        matches!(&**node, HtmlNode::Literal(_)).then_some(false)\n                    } else {\n                        None\n                    }\n                }\n                HtmlTree::Component(comp) => {\n                    if comp.props.props.special.key.is_none() {\n                        return Some(false);\n                    }\n                }\n                HtmlTree::List(list) => {\n                    if list.open.props.key.is_none() {\n                        return Some(false);\n                    }\n                }\n                HtmlTree::Element(element) => {\n                    if element.props.special.key.is_none() {\n                        return Some(false);\n                    }\n                }\n                HtmlTree::If(_) | HtmlTree::For(_) | HtmlTree::Empty => return Some(false),\n            }\n        }\n        Some(true)\n    }\n}\n\nimpl ToTokens for HtmlChildrenTree {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        tokens.extend(self.to_build_vec_token_stream());\n    }\n}\n\npub struct HtmlRootBraced {\n    brace: token::Brace,\n    children: HtmlChildrenTree,\n}\n\nimpl PeekValue<()> for HtmlRootBraced {\n    fn peek(cursor: Cursor) -> Option<()> {\n        cursor.group(Delimiter::Brace).map(|_| ())\n    }\n}\n\nimpl Parse for HtmlRootBraced {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let content;\n        let brace = braced!(content in input);\n        let children = HtmlChildrenTree::parse_delimited(&content)?;\n\n        Ok(HtmlRootBraced { brace, children })\n    }\n}\n\nimpl ToTokens for HtmlRootBraced {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Self { brace, children } = self;\n\n        tokens.extend(quote_spanned! {brace.span.span()=>\n            {\n                ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new(\n                    ::yew::virtual_dom::VList::with_children(#children, ::std::option::Option::None)\n                ))\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/html_tree/tag.rs",
    "content": "use proc_macro2::{Span, TokenStream, TokenTree};\nuse quote::{quote, ToTokens};\nuse syn::parse::{ParseStream, Parser};\nuse syn::Token;\n\n/// Check whether two spans are equal.\n/// The implementation is really silly but I couldn't find another way to do it on stable.\n/// This check isn't required to be fully accurate so it's not the end of the world if it breaks.\nfn span_eq_hack(a: &Span, b: &Span) -> bool {\n    format!(\"{a:?}\") == format!(\"{b:?}\")\n}\n\n/// Change all occurrences of span `from` to `to` in the given error.\nfn error_replace_span(err: syn::Error, from: Span, to: impl ToTokens) -> syn::Error {\n    let err_it = err.into_iter().map(|err| {\n        if span_eq_hack(&err.span(), &from) {\n            syn::Error::new_spanned(&to, err.to_string())\n        } else {\n            err\n        }\n    });\n\n    // SAFETY: all errors have at least one message\n    crate::join_errors(err_it).unwrap_err()\n}\n\n/// Helper type for parsing HTML tags.\n/// The struct only stores the associated tokens, not the content of the tag.\n/// This is meant to mirror the design of delimiters in `syn`.\npub struct TagTokens {\n    pub lt: Token![<],\n    pub div: Option<Token![/]>,\n    pub gt: Token![>],\n}\nimpl TagTokens {\n    /// Parse the content of a start tag.\n    /// The given parse function is called with a `ParseStream`\n    /// containing only the contents of the tag and surrounding `TagTokens`.\n    pub fn parse_start_content<T>(\n        input: ParseStream,\n        parse: impl FnOnce(ParseStream, Self) -> syn::Result<T>,\n    ) -> syn::Result<T> {\n        Self::parse_content(Self::parse_start(input)?, parse)\n    }\n\n    /// Same as `parse_start_content` but for end tags.\n    pub fn parse_end_content<T>(\n        input: ParseStream,\n        parse: impl FnOnce(ParseStream, Self) -> syn::Result<T>,\n    ) -> syn::Result<T> {\n        Self::parse_content(Self::parse_end(input)?, parse)\n    }\n\n    fn parse_content<T>(\n        (tag, content): (Self, TokenStream),\n        parse: impl FnOnce(ParseStream, Self) -> syn::Result<T>,\n    ) -> syn::Result<T> {\n        let scope_spanned = tag.to_spanned();\n        let content_parser = |input: ParseStream| {\n            parse(input, tag).map_err(|err| {\n                // we can't modify the scope span used by `ParseStream`. It just uses the call site\n                // by default. The scope span is used when an error can't be\n                // attributed to a token tree (ex. when the input is empty).\n                // We rewrite all spans to point at the tag which at least narrows down the correct\n                // location. It's not ideal, but it'll have to do until `syn` gives\n                // us more access.\n                error_replace_span(err, Span::call_site(), &scope_spanned)\n            })\n        };\n        content_parser.parse2(content)\n    }\n\n    /// Parse a start tag\n    fn parse_start(input: ParseStream) -> syn::Result<(Self, TokenStream)> {\n        let lt = input.parse()?;\n        let (content, div, gt) = Self::parse_until_end(input)?;\n\n        Ok((Self { lt, div, gt }, content))\n    }\n\n    /// Parse an end tag.\n    /// `div` will always be `Some` for end tags.\n    fn parse_end(input: ParseStream) -> syn::Result<(Self, TokenStream)> {\n        let lt = input.parse()?;\n        let div = Some(input.parse()?);\n\n        let (content, end_div, gt) = Self::parse_until_end(input)?;\n        if end_div.is_some() {\n            return Err(syn::Error::new_spanned(\n                end_div,\n                \"unexpected `/` in this end tag\",\n            ));\n        }\n\n        Ok((Self { lt, div, gt }, content))\n    }\n\n    fn parse_until_end(\n        input: ParseStream,\n    ) -> syn::Result<(TokenStream, Option<Token![/]>, Token![>])> {\n        let mut inner_trees = Vec::new();\n        let mut angle_count: usize = 1;\n        let mut div: Option<Token![/]> = None;\n        let gt: Token![>];\n\n        loop {\n            let next = input.parse()?;\n            if let TokenTree::Punct(punct) = &next {\n                match punct.as_char() {\n                    '/' if angle_count == 1 && input.peek(Token![>]) => {\n                        div = Some(syn::token::Slash {\n                            spans: [punct.span()],\n                        });\n                        gt = input.parse()?;\n                        break;\n                    }\n                    '>' => {\n                        angle_count = angle_count.checked_sub(1).ok_or_else(|| {\n                            syn::Error::new_spanned(\n                                punct,\n                                \"this tag close has no corresponding tag open\",\n                            )\n                        })?;\n                        if angle_count == 0 {\n                            gt = syn::token::Gt {\n                                spans: [punct.span()],\n                            };\n                            break;\n                        }\n                    }\n                    '<' => angle_count += 1,\n                    _ => {}\n                };\n            }\n\n            inner_trees.push(next);\n        }\n\n        Ok((inner_trees.into_iter().collect(), div, gt))\n    }\n\n    /// Generate tokens which can be used in `syn::Error::new_spanned` to span the entire tag.\n    /// This is to work around the limitation of being unable to manually join spans on stable.\n    pub fn to_spanned(&self) -> impl ToTokens {\n        let Self { lt, gt, .. } = self;\n        quote! {#lt #gt}\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/lib.rs",
    "content": "//! This crate provides Yew's procedural macro `html!` which allows using JSX-like syntax\n//! for generating html and the `Properties` derive macro for deriving the `Properties` trait\n//! for components.\n//!\n//! ```\n//! use yew::prelude::*;\n//!\n//! struct Component;\n//!\n//! #[derive(Properties, PartialEq)]\n//! struct Props {\n//!     prop: String,\n//! }\n//!\n//! # enum Msg { Submit }\n//! #\n//! # impl yew::Component for Component {\n//! #     type Message = Msg;\n//! #     type Properties = Props;\n//! #     fn create(_ctx: &Context<Self>) -> Self {\n//! #         unimplemented!()\n//! #     }\n//! #\n//! #\n//! #     fn view(&self, ctx: &Context<Self>) -> Html {\n//! #\n//! // ...\n//!\n//! html! {\n//!   <div>\n//!     <button onclick={ctx.link().callback(|_| Msg::Submit)}>\n//!       { \"Submit\" }\n//!     </button>\n//!     <>\n//!       <Component prop=\"first\" />\n//!       <Component prop=\"second\" />\n//!     </>\n//!   </div>\n//! }\n//! #\n//! #     }\n//! # }\n//! #\n//! # fn main() {}\n//! ```\n//!\n//! Please refer to [https://github.com/yewstack/yew](https://github.com/yewstack/yew) for how to set this up.\n\nmod classes;\nmod derive_props;\nmod function_component;\nmod hook;\nmod html_tree;\nmod props;\nmod stringify;\nmod use_prepared_state;\nmod use_transitive_state;\n\nuse derive_props::DerivePropsInput;\nuse function_component::{function_component_impl, FunctionComponent, FunctionComponentName};\nuse hook::{hook_impl, HookFn};\nuse html_tree::{HtmlRoot, HtmlRootVNode};\nuse proc_macro::TokenStream;\nuse quote::ToTokens;\nuse syn::buffer::Cursor;\nuse syn::parse_macro_input;\nuse use_prepared_state::PreparedState;\nuse use_transitive_state::TransitiveState;\n\ntrait Peek<'a, T> {\n    fn peek(cursor: Cursor<'a>) -> Option<(T, Cursor<'a>)>;\n}\n\ntrait PeekValue<T> {\n    fn peek(cursor: Cursor) -> Option<T>;\n}\n\nfn non_capitalized_ascii(string: &str) -> bool {\n    if !string.is_ascii() {\n        false\n    } else if let Some(c) = string.bytes().next() {\n        c.is_ascii_lowercase()\n    } else {\n        false\n    }\n}\n\n/// Combine multiple `syn` errors into a single one.\n/// Returns `Result::Ok` if the given iterator is empty\nfn join_errors(mut it: impl Iterator<Item = syn::Error>) -> syn::Result<()> {\n    it.next().map_or(Ok(()), |mut err| {\n        for other in it {\n            err.combine(other);\n        }\n        Err(err)\n    })\n}\n\nfn is_ide_completion() -> bool {\n    match std::env::var_os(\"RUST_IDE_PROC_MACRO_COMPLETION_DUMMY_IDENTIFIER\") {\n        None => false,\n        Some(dummy_identifier) => !dummy_identifier.is_empty(),\n    }\n}\n\n#[proc_macro_derive(Properties, attributes(prop_or, prop_or_else, prop_or_default))]\npub fn derive_props(input: TokenStream) -> TokenStream {\n    let mut input = parse_macro_input!(input as DerivePropsInput);\n    input.normalise();\n    TokenStream::from(input.into_token_stream())\n}\n\n#[proc_macro_error::proc_macro_error]\n#[proc_macro]\npub fn html_nested(input: TokenStream) -> TokenStream {\n    let root = parse_macro_input!(input as HtmlRoot);\n    TokenStream::from(root.into_token_stream())\n}\n\n#[proc_macro_error::proc_macro_error]\n#[proc_macro]\npub fn html(input: TokenStream) -> TokenStream {\n    let root = parse_macro_input!(input as HtmlRootVNode);\n    TokenStream::from(root.into_token_stream())\n}\n\n#[proc_macro]\npub fn props(input: TokenStream) -> TokenStream {\n    let props = parse_macro_input!(input as props::PropsMacroInput);\n    TokenStream::from(props.into_token_stream())\n}\n\n#[proc_macro]\npub fn classes(input: TokenStream) -> TokenStream {\n    let classes = parse_macro_input!(input as classes::Classes);\n    TokenStream::from(classes.into_token_stream())\n}\n\n#[proc_macro_error::proc_macro_error]\n#[proc_macro_attribute]\npub fn function_component(attr: TokenStream, item: TokenStream) -> TokenStream {\n    let item = parse_macro_input!(item as FunctionComponent);\n    let attr = parse_macro_input!(attr as FunctionComponentName);\n\n    function_component_impl(attr, item)\n        .unwrap_or_else(|err| err.to_compile_error())\n        .into()\n}\n\n#[proc_macro_error::proc_macro_error]\n#[proc_macro_attribute]\npub fn hook(attr: TokenStream, item: TokenStream) -> TokenStream {\n    let item = parse_macro_input!(item as HookFn);\n\n    if let Some(m) = proc_macro2::TokenStream::from(attr).into_iter().next() {\n        return syn::Error::new_spanned(m, \"hook attribute does not accept any arguments\")\n            .into_compile_error()\n            .into();\n    }\n\n    hook_impl(item)\n        .unwrap_or_else(|err| err.to_compile_error())\n        .into()\n}\n\n#[proc_macro]\npub fn use_prepared_state_with_closure(input: TokenStream) -> TokenStream {\n    let prepared_state = parse_macro_input!(input as PreparedState);\n    prepared_state.to_token_stream_with_closure().into()\n}\n\n#[proc_macro]\npub fn use_prepared_state_without_closure(input: TokenStream) -> TokenStream {\n    let prepared_state = parse_macro_input!(input as PreparedState);\n    prepared_state.to_token_stream_without_closure().into()\n}\n\n#[proc_macro]\npub fn use_transitive_state_with_closure(input: TokenStream) -> TokenStream {\n    let transitive_state = parse_macro_input!(input as TransitiveState);\n    transitive_state.to_token_stream_with_closure().into()\n}\n\n#[proc_macro]\npub fn use_transitive_state_without_closure(input: TokenStream) -> TokenStream {\n    let transitive_state = parse_macro_input!(input as TransitiveState);\n    transitive_state.to_token_stream_without_closure().into()\n}\n"
  },
  {
    "path": "packages/yew-macro/src/props/component.rs",
    "content": "use std::convert::TryFrom;\n\nuse proc_macro2::{Ident, Span, TokenStream};\nuse quote::{quote, quote_spanned, ToTokens};\nuse syn::parse::{Parse, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::token::DotDot;\nuse syn::Expr;\n\nuse super::{Prop, Props, SpecialProps, CHILDREN_LABEL};\n\nfn is_none_expr(expr: &Expr) -> bool {\n    matches!(\n        expr,\n        Expr::Path(syn::ExprPath {\n            attrs,\n            qself: None,\n            path,\n        }) if attrs.is_empty() && path.is_ident(\"None\")\n    )\n}\n\nstruct BaseExpr {\n    pub dot_dot: DotDot,\n    pub expr: Expr,\n}\n\nimpl Parse for BaseExpr {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let dot_dot = input.parse()?;\n        let expr = input.parse().map_err(|expr_error| {\n            let mut error =\n                syn::Error::new_spanned(dot_dot, \"expected base props expression after `..`\");\n            error.combine(expr_error);\n            error\n        })?;\n        Ok(Self { dot_dot, expr })\n    }\n}\n\nimpl ToTokens for BaseExpr {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let BaseExpr { dot_dot, expr } = self;\n        tokens.extend(quote! { #dot_dot #expr });\n    }\n}\n\npub struct ComponentProps {\n    pub props: Props,\n    base_expr: Option<Expr>,\n}\nimpl ComponentProps {\n    /// Get the special props supported by both variants\n    pub fn special(&self) -> &SpecialProps {\n        &self.props.special\n    }\n\n    // check if the `children` prop is given explicitly\n    pub fn children(&self) -> Option<&Prop> {\n        self.props.get_by_label(CHILDREN_LABEL)\n    }\n\n    fn prop_validation_tokens(&self, props_ty: impl ToTokens, has_children: bool) -> TokenStream {\n        let props_ident = Ident::new(\"__yew_props\", props_ty.span());\n        let check_children = if has_children {\n            Some(quote_spanned! {props_ty.span()=>\n                let _ = #props_ident.children;\n            })\n        } else {\n            None\n        };\n\n        let check_props: TokenStream = self\n            .props\n            .iter()\n            .map(|Prop { label, .. }| {\n                quote_spanned! {Span::call_site().located_at(label.span())=>\n                    let _ = &#props_ident.#label;\n                }\n            })\n            .collect();\n\n        quote_spanned! {props_ty.span()=>\n            #[allow(clippy::no_effect)]\n            if false {\n                let _ = |#props_ident: #props_ty| {\n                    #check_children\n                    #check_props\n                };\n            };\n        }\n    }\n\n    pub fn build_properties_tokens<CR: ToTokens>(\n        &self,\n        props_ty: impl ToTokens,\n        children_renderer: Option<CR>,\n    ) -> TokenStream {\n        let has_children = children_renderer.is_some();\n        let validate_props = self.prop_validation_tokens(&props_ty, has_children);\n        let build_props = match &self.base_expr {\n            None => {\n                let builder_ident = Ident::new(\"__yew_props\", props_ty.span());\n                let token_ident = Ident::new(\n                    \"__yew_required_props_token\",\n                    props_ty.span().resolved_at(Span::mixed_site()),\n                );\n\n                let init_builder = quote_spanned! {props_ty.span()=>\n                    let mut #builder_ident = <#props_ty as ::yew::html::Properties>::builder();\n                    let #token_ident = ::yew::html::AssertAllProps;\n                };\n                let set_props = self.props.iter().map(|Prop { label, value, .. }| {\n                    if is_none_expr(value) {\n                        let none_setter = Ident::new(\n                            &format!(\"{}_none\", label),\n                            label.span().resolved_at(Span::mixed_site()),\n                        );\n                        quote_spanned! {value.span()=>\n                            let #token_ident = #builder_ident.#none_setter(#token_ident);\n                        }\n                    } else {\n                        quote_spanned! {value.span()=>\n                            let #token_ident = #builder_ident.#label(#token_ident, #value);\n                        }\n                    }\n                });\n                let set_children = children_renderer.map(|children| {\n                    quote_spanned! {props_ty.span()=>\n                        let #token_ident = #builder_ident.children(#token_ident, #children);\n                    }\n                });\n                let build_builder = quote_spanned! {props_ty.span()=>\n                    ::yew::html::Buildable::prepare_build(#builder_ident, &#token_ident).build()\n                };\n\n                quote! {\n                    #init_builder\n                    #( #set_props )*\n                    #set_children\n                    #build_builder\n                }\n            }\n            // Builder pattern is unnecessary in this case, since the base expression guarantees\n            // all values are initialized\n            Some(expr) => {\n                let ident = Ident::new(\"__yew_props\", props_ty.span());\n                let set_props = self.props.iter().map(|Prop { label, value, .. }| {\n                    if is_none_expr(value) {\n                        quote_spanned! {value.span().resolved_at(Span::call_site())=>\n                            #ident.#label = ::std::option::Option::None;\n                        }\n                    } else {\n                        quote_spanned! {value.span().resolved_at(Span::call_site())=>\n                            #ident.#label = ::yew::html::IntoPropValue::into_prop_value(#value);\n                        }\n                    }\n                });\n                let set_children = children_renderer.map(|children| {\n                    quote_spanned! {props_ty.span()=>\n                        #ident.children = ::yew::html::IntoPropValue::into_prop_value(#children);\n                    }\n                });\n                let init_base = quote_spanned! {expr.span().resolved_at(Span::call_site())=>\n                    let mut #ident: #props_ty = #expr;\n                };\n\n                quote! {\n                    #init_base\n                    #(#set_props)*\n                    #set_children\n                    #ident\n                }\n            }\n        };\n\n        quote! {\n            {\n                #validate_props\n                #build_props\n            }\n        }\n    }\n}\n\nimpl Parse for ComponentProps {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let props = validate(input.parse()?)?;\n        let base_expr = if input.is_empty() {\n            None\n        } else {\n            Some(input.parse::<BaseExpr>()?)\n        };\n\n        if input.is_empty() {\n            let base_expr = base_expr.map(|base| base.expr);\n            Ok(Self { props, base_expr })\n        } else {\n            Err(syn::Error::new_spanned(\n                base_expr,\n                \"base props expression must appear last in list of props\",\n            ))\n        }\n    }\n}\n\nimpl TryFrom<Props> for ComponentProps {\n    type Error = syn::Error;\n\n    fn try_from(props: Props) -> Result<Self, Self::Error> {\n        Ok(Self {\n            props: validate(props)?,\n            base_expr: None,\n        })\n    }\n}\n\nfn validate(props: Props) -> Result<Props, syn::Error> {\n    props.check_no_duplicates()?;\n    props.check_all(|prop| {\n        if !prop.label.extended.is_empty() {\n            Err(syn::Error::new_spanned(\n                &prop.label,\n                \"expected a valid Rust identifier\",\n            ))\n        } else {\n            Ok(())\n        }\n    })?;\n\n    Ok(props)\n}\n"
  },
  {
    "path": "packages/yew-macro/src/props/element.rs",
    "content": "use std::collections::HashSet;\nuse std::sync::LazyLock;\n\nuse syn::parse::{Parse, ParseStream};\n\nuse super::{Prop, Props, SpecialProps};\n\npub struct ElementProps {\n    pub attributes: Vec<Prop>,\n    pub listeners: Vec<Prop>,\n    pub classes: Option<Prop>,\n    pub booleans: Vec<Prop>,\n    pub value: Option<Prop>,\n    pub defaultvalue: Option<Prop>,\n    pub checked: Option<Prop>,\n    pub special: SpecialProps,\n}\n\nimpl Parse for ElementProps {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let mut props = input.parse::<Props>()?;\n\n        let listeners =\n            props.drain_filter(|prop| LISTENER_SET.contains(prop.label.to_string().as_str()));\n\n        // Multiple listener attributes are allowed, but no others\n        props.check_no_duplicates()?;\n\n        let booleans =\n            props.drain_filter(|prop| BOOLEAN_SET.contains(prop.label.to_string().as_str()));\n\n        let classes = props.pop(\"class\");\n        let value = props.pop(\"value\");\n        let checked = props.pop(\"checked\");\n        let defaultvalue = props.pop(\"defaultvalue\");\n        let special = props.special;\n\n        Ok(Self {\n            attributes: props.prop_list.into_vec(),\n            classes,\n            listeners: listeners.into_vec(),\n            checked,\n            booleans: booleans.into_vec(),\n            value,\n            special,\n            defaultvalue,\n        })\n    }\n}\n\nstatic BOOLEAN_SET: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {\n    [\n        // Living Standard\n        // From: https://html.spec.whatwg.org/#attributes-3\n        // where `Value` = Boolean attribute\n        // Note: `checked` is uniquely handled in the html! macro.\n        \"allowfullscreen\",\n        \"async\",\n        \"autofocus\",\n        \"autoplay\",\n        \"controls\",\n        \"default\",\n        \"defer\",\n        \"disabled\",\n        \"formnovalidate\",\n        \"hidden\",\n        \"inert\",\n        \"ismap\",\n        \"itemscope\",\n        \"loop\",\n        \"multiple\",\n        \"muted\",\n        \"nomodule\",\n        \"novalidate\",\n        \"open\",\n        \"playsinline\",\n        \"readonly\",\n        \"required\",\n        \"reversed\",\n        \"selected\",\n        \"truespeed\",\n        // Not-yet-standardized\n        \"webkitdirectory\",\n    ]\n    .into()\n});\n\nstatic LISTENER_SET: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {\n    [\n        // Living Standard\n        // From: https://html.spec.whatwg.org/multipage/webappapis.html#globaleventhandlers\n        \"onabort\",\n        \"onauxclick\",\n        \"onblur\",\n        \"oncancel\",\n        \"oncanplay\",\n        \"oncanplaythrough\",\n        \"onchange\",\n        \"onclick\",\n        \"onclose\",\n        \"oncontextmenu\",\n        \"oncuechange\",\n        \"ondblclick\",\n        \"ondrag\",\n        \"ondragend\",\n        \"ondragenter\",\n        \"ondragexit\",\n        \"ondragleave\",\n        \"ondragover\",\n        \"ondragstart\",\n        \"ondrop\",\n        \"ondurationchange\",\n        \"onemptied\",\n        \"onended\",\n        \"onerror\",\n        \"onfocus\",\n        // onfocusin + onfocusout not in standard but added due to browser support\n        // see issue 1896: https://github.com/yewstack/yew/issues/1896\n        \"onfocusin\",\n        \"onfocusout\",\n        \"onformdata\",\n        \"oninput\",\n        \"oninvalid\",\n        \"onkeydown\",\n        \"onkeypress\",\n        \"onkeyup\",\n        \"onload\",\n        \"onloadeddata\",\n        \"onloadedmetadata\",\n        \"onloadstart\",\n        \"onmousedown\",\n        \"onmouseenter\",\n        \"onmouseleave\",\n        \"onmousemove\",\n        \"onmouseout\",\n        \"onmouseover\",\n        \"onmouseup\",\n        \"onpause\",\n        \"onplay\",\n        \"onplaying\",\n        \"onprogress\",\n        \"onratechange\",\n        \"onreset\",\n        \"onresize\",\n        \"onscroll\",\n        \"onsecuritypolicyviolation\",\n        \"onseeked\",\n        \"onseeking\",\n        \"onselect\",\n        \"onslotchange\",\n        \"onstalled\",\n        \"onsubmit\",\n        \"onsuspend\",\n        \"ontimeupdate\",\n        \"ontoggle\",\n        \"onvolumechange\",\n        \"onwaiting\",\n        \"onwheel\",\n        // Standard HTML Document and Element\n        // From: https://html.spec.whatwg.org/multipage/webappapis.html#documentandelementeventhandlers\n        \"oncopy\",\n        \"oncut\",\n        \"onpaste\",\n        // Others\n        // From: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers\n        \"onanimationcancel\",\n        \"onanimationend\",\n        \"onanimationiteration\",\n        \"onanimationstart\",\n        \"ongotpointercapture\",\n        \"onloadend\",\n        \"onlostpointercapture\",\n        \"onpointercancel\",\n        \"onpointerdown\",\n        \"onpointerenter\",\n        \"onpointerleave\",\n        \"onpointerlockchange\",\n        \"onpointerlockerror\",\n        \"onpointermove\",\n        \"onpointerout\",\n        \"onpointerover\",\n        \"onpointerup\",\n        \"onselectionchange\",\n        \"onselectstart\",\n        \"onshow\",\n        \"ontouchcancel\",\n        \"ontouchend\",\n        \"ontouchmove\",\n        \"ontouchstart\",\n        \"ontransitioncancel\",\n        \"ontransitionend\",\n        \"ontransitionrun\",\n        \"ontransitionstart\",\n    ]\n    .into()\n});\n"
  },
  {
    "path": "packages/yew-macro/src/props/mod.rs",
    "content": "mod component;\nmod element;\nmod prop;\nmod prop_macro;\n\npub use component::*;\npub use element::*;\npub use prop::*;\npub use prop_macro::PropsMacroInput;\n\nconst CHILDREN_LABEL: &str = \"children\";\n"
  },
  {
    "path": "packages/yew-macro/src/props/prop.rs",
    "content": "use std::convert::TryFrom;\nuse std::ops::{Deref, DerefMut};\n\nuse proc_macro2::{Spacing, Span, TokenStream, TokenTree};\nuse quote::{quote, quote_spanned};\nuse syn::parse::{Parse, ParseBuffer, ParseStream};\nuse syn::spanned::Spanned;\nuse syn::token::Brace;\nuse syn::{braced, Block, Expr, ExprBlock, ExprMacro, ExprPath, ExprRange, Stmt, Token};\n\nuse crate::html_tree::HtmlDashedName;\nuse crate::stringify::Stringify;\n\n#[derive(Copy, Clone)]\npub enum PropDirective {\n    ApplyAsProperty(Token![~]),\n}\n\npub struct Prop {\n    pub directive: Option<PropDirective>,\n    pub label: HtmlDashedName,\n    /// Punctuation between `label` and `value`.\n    pub value: Expr,\n}\n\nimpl Parse for Prop {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let directive = input\n            .parse::<Token![~]>()\n            .map(PropDirective::ApplyAsProperty)\n            .ok();\n        if input.peek(Brace) {\n            Self::parse_shorthand_prop_assignment(input, directive)\n        } else {\n            Self::parse_prop_assignment(input, directive)\n        }\n    }\n}\n\n/// Helpers for parsing props\nimpl Prop {\n    /// Parse a prop using the shorthand syntax `{value}`, short for `value={value}`\n    /// This only allows for labels with no hyphens, as it would otherwise create\n    /// an ambiguity in the syntax\n    fn parse_shorthand_prop_assignment(\n        input: ParseStream,\n        directive: Option<PropDirective>,\n    ) -> syn::Result<Self> {\n        let value;\n        let _brace = braced!(value in input);\n        let expr = value.parse::<Expr>()?;\n        let label = if let Expr::Path(ExprPath {\n            ref attrs,\n            qself: None,\n            ref path,\n        }) = expr\n        {\n            if let (Some(ident), true) = (path.get_ident(), attrs.is_empty()) {\n                Ok(HtmlDashedName::from(ident.clone()))\n            } else {\n                Err(syn::Error::new_spanned(\n                    path,\n                    \"only simple identifiers are allowed in the shorthand property syntax\",\n                ))\n            }\n        } else {\n            return Err(syn::Error::new_spanned(\n                expr,\n                \"missing label for property value. If trying to use the shorthand property \\\n                 syntax, only identifiers may be used\",\n            ));\n        }?;\n\n        Ok(Self {\n            label,\n            value: expr,\n            directive,\n        })\n    }\n\n    /// Parse a prop of the form `label={value}`\n    fn parse_prop_assignment(\n        input: ParseStream,\n        directive: Option<PropDirective>,\n    ) -> syn::Result<Self> {\n        let label = input.parse::<HtmlDashedName>()?;\n        let equals = input.parse::<Token![=]>().map_err(|_| {\n            syn::Error::new_spanned(\n                &label,\n                format!(\n                    \"`{label}` doesn't have a value. (hint: set the value to `true` or `false` \\\n                     for boolean attributes)\"\n                ),\n            )\n        })?;\n        if input.is_empty() {\n            return Err(syn::Error::new_spanned(\n                equals,\n                \"expected an expression following this equals sign\",\n            ));\n        }\n\n        let value = parse_prop_value(input)?;\n        Ok(Self {\n            label,\n            value,\n            directive,\n        })\n    }\n}\n\nfn parse_prop_value(input: &ParseBuffer) -> syn::Result<Expr> {\n    if input.peek(Brace) {\n        strip_braces(input.parse()?)\n    } else {\n        let expr = if let Some(ExprRange {\n            start: Some(start), ..\n        }) = range_expression_peek(input)\n        {\n            // If a range expression is seen, treat the left-side expression as the value\n            // and leave the right-side expression to be parsed as a base expression\n            advance_until_next_dot2(input)?;\n            *start\n        } else {\n            input.parse()?\n        };\n\n        match &expr {\n            Expr::Lit(_) => Ok(expr),\n            ref exp => Err(syn::Error::new_spanned(\n                &expr,\n                format!(\n                    \"the property value must be either a literal or enclosed in braces. Consider \\\n                     adding braces around your expression.: {exp:#?}\"\n                ),\n            )),\n        }\n    }\n}\n\nfn strip_braces(block: ExprBlock) -> syn::Result<Expr> {\n    match block {\n        ExprBlock {\n            block: Block { mut stmts, .. },\n            ..\n        } if stmts.len() == 1 => {\n            let stmt = stmts.remove(0);\n            match stmt {\n                Stmt::Expr(expr, None) => Ok(expr),\n                Stmt::Macro(mac) => Ok(Expr::Macro(ExprMacro {\n                    attrs: vec![],\n                    mac: mac.mac,\n                })),\n                // See issue #2267, we want to parse macro invocations as expressions\n                Stmt::Item(syn::Item::Macro(mac))\n                    if mac.ident.is_none() && mac.semi_token.is_none() =>\n                {\n                    Ok(Expr::Macro(syn::ExprMacro {\n                        attrs: mac.attrs,\n                        mac: mac.mac,\n                    }))\n                }\n                Stmt::Expr(_, Some(semi)) => Err(syn::Error::new_spanned(\n                    semi,\n                    \"only an expression may be assigned as a property. Consider removing this \\\n                     semicolon\",\n                )),\n                _ => Err(syn::Error::new_spanned(\n                    stmt,\n                    \"only an expression may be assigned as a property\",\n                )),\n            }\n        }\n        block => Ok(Expr::Block(block)),\n    }\n}\n\n// Without advancing cursor, returns the range expression at the current cursor position if any\nfn range_expression_peek(input: &ParseBuffer) -> Option<ExprRange> {\n    match input.fork().parse::<Expr>().ok()? {\n        Expr::Range(range) => Some(range),\n        _ => None,\n    }\n}\n\nfn advance_until_next_dot2(input: &ParseBuffer) -> syn::Result<()> {\n    input.step(|cursor| {\n        let mut rest = *cursor;\n        let mut first_dot = None;\n        while let Some((tt, next)) = rest.token_tree() {\n            match &tt {\n                TokenTree::Punct(punct) if punct.as_char() == '.' => {\n                    if let Some(first_dot) = first_dot {\n                        return Ok(((), first_dot));\n                    } else {\n                        // Only consider dot as potential first if there is no spacing after it\n                        first_dot = if punct.spacing() == Spacing::Joint {\n                            Some(rest)\n                        } else {\n                            None\n                        };\n                    }\n                }\n                _ => {\n                    first_dot = None;\n                }\n            }\n            rest = next;\n        }\n        Err(cursor.error(\"no `..` found in expression\"))\n    })\n}\n\n/// List of props sorted in alphabetical order*.\n///\n/// \\*The \"children\" prop always comes last to match the behaviour of the `Properties` derive macro.\n///\n/// The list may contain multiple props with the same label.\n/// Use `check_no_duplicates` to ensure that there are no duplicates.\npub struct PropList(Vec<Prop>);\nimpl PropList {\n    /// Create a new `SortedPropList` from a vector of props.\n    /// The given `props` doesn't need to be sorted.\n    pub fn new(props: Vec<Prop>) -> Self {\n        Self(props)\n    }\n\n    fn position(&self, key: &str) -> Option<usize> {\n        self.0.iter().position(|it| it.label.to_string() == key)\n    }\n\n    /// Get the first prop with the given key.\n    pub fn get_by_label(&self, key: &str) -> Option<&Prop> {\n        self.0.iter().find(|it| it.label.to_string() == key)\n    }\n\n    /// Pop the first prop with the given key.\n    pub fn pop(&mut self, key: &str) -> Option<Prop> {\n        self.position(key).map(|i| self.0.remove(i))\n    }\n\n    /// Pop the prop with the given key and error if there are multiple ones.\n    pub fn pop_unique(&mut self, key: &str) -> syn::Result<Option<Prop>> {\n        let prop = self.pop(key);\n        if prop.is_some() {\n            if let Some(other_prop) = self.get_by_label(key) {\n                return Err(syn::Error::new_spanned(\n                    &other_prop.label,\n                    format!(\"`{key}` can only be specified once\"),\n                ));\n            }\n        }\n\n        Ok(prop)\n    }\n\n    /// Turn the props into a vector of `Prop`.\n    pub fn into_vec(self) -> Vec<Prop> {\n        self.0\n    }\n\n    /// Iterate over all duplicate props in order of appearance.\n    fn iter_duplicates(&self) -> impl Iterator<Item = &Prop> {\n        self.0.windows(2).filter_map(|pair| {\n            let (a, b) = (&pair[0], &pair[1]);\n\n            if a.label == b.label {\n                Some(b)\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Remove and return all props for which `filter` returns `true`.\n    pub fn drain_filter(&mut self, filter: impl FnMut(&Prop) -> bool) -> Self {\n        let (drained, others) = self.0.drain(..).partition(filter);\n        self.0 = others;\n        Self(drained)\n    }\n\n    /// Run the given function for all props and aggregate the errors.\n    /// If there's at least one error, the result will be `Result::Err`.\n    pub fn check_all(&self, f: impl FnMut(&Prop) -> syn::Result<()>) -> syn::Result<()> {\n        crate::join_errors(self.0.iter().map(f).filter_map(Result::err))\n    }\n\n    /// Return an error for all duplicate props.\n    pub fn check_no_duplicates(&self) -> syn::Result<()> {\n        crate::join_errors(self.iter_duplicates().map(|prop| {\n            syn::Error::new_spanned(\n                &prop.label,\n                format!(\n                    \"`{}` can only be specified once but is given here again\",\n                    prop.label\n                ),\n            )\n        }))\n    }\n}\nimpl Parse for PropList {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let mut props: Vec<Prop> = Vec::new();\n        // Stop parsing props if a base expression preceded by `..` is reached\n        while !input.is_empty() && !input.peek(Token![..]) {\n            props.push(input.parse()?);\n        }\n\n        Ok(Self::new(props))\n    }\n}\nimpl Deref for PropList {\n    type Target = [Prop];\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n#[derive(Default)]\npub struct SpecialProps {\n    pub node_ref: Option<Prop>,\n    pub key: Option<Prop>,\n}\nimpl SpecialProps {\n    const KEY_LABEL: &'static str = \"key\";\n    const REF_LABEL: &'static str = \"ref\";\n\n    fn pop_from(props: &mut PropList) -> syn::Result<Self> {\n        let node_ref = props.pop_unique(Self::REF_LABEL)?;\n        let key = props.pop_unique(Self::KEY_LABEL)?;\n        Ok(Self { node_ref, key })\n    }\n\n    fn iter(&self) -> impl Iterator<Item = &Prop> {\n        self.node_ref.as_ref().into_iter().chain(self.key.as_ref())\n    }\n\n    /// Run the given function for all props and aggregate the errors.\n    /// If there's at least one error, the result will be `Result::Err`.\n    pub fn check_all(&self, f: impl FnMut(&Prop) -> syn::Result<()>) -> syn::Result<()> {\n        crate::join_errors(self.iter().map(f).filter_map(Result::err))\n    }\n\n    pub fn wrap_node_ref_attr(&self) -> TokenStream {\n        self.node_ref\n            .as_ref()\n            .map(|attr| {\n                let value = &attr.value;\n                quote_spanned! {value.span().resolved_at(Span::call_site())=>\n                    ::yew::html::IntoPropValue::<::yew::html::NodeRef>\n                    ::into_prop_value(#value)\n                }\n            })\n            .unwrap_or(quote! { ::std::default::Default::default() })\n    }\n\n    pub fn wrap_key_attr(&self) -> TokenStream {\n        self.key\n            .as_ref()\n            .map(|attr| {\n                let value = attr.value.optimize_literals();\n                quote_spanned! {value.span().resolved_at(Span::call_site())=>\n                    ::std::option::Option::Some(\n                        ::std::convert::Into::<::yew::virtual_dom::Key>::into(#value)\n                    )\n                }\n            })\n            .unwrap_or(quote! { ::std::option::Option::None })\n    }\n}\n\npub struct Props {\n    pub special: SpecialProps,\n    pub prop_list: PropList,\n}\nimpl Parse for Props {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        Self::try_from(input.parse::<PropList>()?)\n    }\n}\nimpl Deref for Props {\n    type Target = PropList;\n\n    fn deref(&self) -> &Self::Target {\n        &self.prop_list\n    }\n}\nimpl DerefMut for Props {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.prop_list\n    }\n}\n\nimpl TryFrom<PropList> for Props {\n    type Error = syn::Error;\n\n    fn try_from(mut prop_list: PropList) -> Result<Self, Self::Error> {\n        let special = SpecialProps::pop_from(&mut prop_list)?;\n        Ok(Self { special, prop_list })\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/props/prop_macro.rs",
    "content": "use std::convert::TryInto;\n\nuse proc_macro2::TokenStream;\nuse quote::{quote_spanned, ToTokens};\nuse syn::parse::{Parse, ParseStream};\nuse syn::punctuated::Punctuated;\nuse syn::spanned::Spanned;\nuse syn::token::Brace;\nuse syn::{Expr, Token, TypePath};\n\nuse super::{ComponentProps, Prop, PropList, Props};\nuse crate::html_tree::HtmlDashedName;\n\n/// Pop from `Punctuated` without leaving it in a state where it has trailing punctuation.\nfn pop_last_punctuated<T, P>(punctuated: &mut Punctuated<T, P>) -> Option<T> {\n    let value = punctuated.pop().map(|pair| pair.into_value());\n    // remove the 2nd last value and push it right back to remove the trailing punctuation\n    if let Some(pair) = punctuated.pop() {\n        punctuated.push_value(pair.into_value());\n    }\n    value\n}\n\n/// Check if the given type path looks like an associated `Properties` type.\nfn is_associated_properties(ty: &TypePath) -> bool {\n    let mut segments_it = ty.path.segments.iter();\n    if let Some(seg) = segments_it.next_back() {\n        // if the last segment is `Properties` ...\n        if seg.ident == \"Properties\" {\n            if let Some(seg) = segments_it.next_back() {\n                // ... and we can be reasonably sure that the previous segment is a component ...\n                if !crate::non_capitalized_ascii(&seg.ident.to_string()) {\n                    // ... then we assume that this is an associated type like\n                    // `Component::Properties`\n                    return true;\n                }\n            }\n        }\n    }\n\n    false\n}\n\nstruct PropValue {\n    label: HtmlDashedName,\n    value: Expr,\n}\nimpl Parse for PropValue {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let label = input.parse()?;\n        let value = if input.peek(Token![:]) {\n            let _colon_token: Token![:] = input.parse()?;\n            input.parse()?\n        } else {\n            syn::parse_quote!(#label)\n        };\n        Ok(Self { label, value })\n    }\n}\n\nimpl From<PropValue> for Prop {\n    fn from(prop_value: PropValue) -> Prop {\n        let PropValue { label, value } = prop_value;\n        Prop {\n            label,\n            value,\n            directive: None,\n        }\n    }\n}\n\nstruct PropsExpr {\n    ty: TypePath,\n    _brace_token: Brace,\n    fields: Punctuated<PropValue, Token![,]>,\n}\nimpl Parse for PropsExpr {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let mut ty: TypePath = input.parse()?;\n\n        // if the type isn't already qualified (`<x as y>`) and it's an associated type\n        // (`MyComp::Properties`) ...\n        if ty.qself.is_none() && is_associated_properties(&ty) {\n            pop_last_punctuated(&mut ty.path.segments);\n            // .. transform it into a \"qualified-self\" type\n            ty = syn::parse2(quote_spanned! {ty.span()=>\n                <#ty as ::yew::html::Component>::Properties\n            })?;\n        }\n\n        let content;\n        let brace_token = syn::braced!(content in input);\n        let fields = content.parse_terminated(PropValue::parse, Token![,])?;\n        Ok(Self {\n            ty,\n            _brace_token: brace_token,\n            fields,\n        })\n    }\n}\n\npub struct PropsMacroInput {\n    ty: TypePath,\n    props: ComponentProps,\n}\nimpl Parse for PropsMacroInput {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let PropsExpr { ty, fields, .. } = input.parse()?;\n        let prop_list = PropList::new(fields.into_iter().map(Into::into).collect());\n        let props: Props = prop_list.try_into()?;\n        props.special.check_all(|prop| {\n            let label = &prop.label;\n            Err(syn::Error::new_spanned(\n                label,\n                \"special props cannot be specified in the `props!` macro\",\n            ))\n        })?;\n        Ok(Self {\n            ty,\n            props: props.try_into()?,\n        })\n    }\n}\nimpl ToTokens for PropsMacroInput {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Self { ty, props } = self;\n\n        tokens.extend(props.build_properties_tokens(ty, None::<TokenStream>))\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/stringify.rs",
    "content": "use std::borrow::Cow;\nuse std::mem::size_of;\n\nuse proc_macro2::{Span, TokenStream};\nuse quote::{quote_spanned, ToTokens};\nuse syn::spanned::Spanned;\nuse syn::{Expr, Lit, LitStr};\n\n/// Stringify a value at runtime.\nfn stringify_at_runtime(src: impl ToTokens) -> TokenStream {\n    quote_spanned! {src.span().resolved_at(Span::call_site())=>\n        ::std::convert::Into::<::yew::virtual_dom::AttrValue>::into(#src)\n    }\n}\n\n/// Create `AttrValue` construction calls.\n///\n/// This is deliberately not implemented for strings to preserve spans.\npub trait Stringify {\n    /// Try to turn the value into a string literal.\n    fn try_into_lit(&self) -> Option<LitStr>;\n    /// Create `AttrValue` however possible.\n    fn stringify(&self) -> TokenStream;\n\n    /// Optimize literals to `&'static str`, otherwise keep the value as is.\n    fn optimize_literals(&self) -> TokenStream\n    where\n        Self: ToTokens,\n    {\n        self.optimize_literals_tagged().to_token_stream()\n    }\n\n    /// Like `optimize_literals` but tags static or dynamic strings with [Value]\n    fn optimize_literals_tagged(&self) -> Value\n    where\n        Self: ToTokens,\n    {\n        if let Some(lit) = self.try_into_lit() {\n            Value::Static(lit.to_token_stream())\n        } else {\n            Value::Dynamic(self.to_token_stream())\n        }\n    }\n}\nimpl<T: Stringify + ?Sized> Stringify for &T {\n    fn try_into_lit(&self) -> Option<LitStr> {\n        (*self).try_into_lit()\n    }\n\n    fn stringify(&self) -> TokenStream {\n        (*self).stringify()\n    }\n}\n\n/// A stringified value that can be either static (known at compile time) or dynamic (known only at\n/// runtime)\npub enum Value {\n    Static(TokenStream),\n    Dynamic(TokenStream),\n}\n\nimpl ToTokens for Value {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        tokens.extend(match self {\n            Value::Static(tt) | Value::Dynamic(tt) => tt.clone(),\n        });\n    }\n}\n\nimpl Stringify for LitStr {\n    fn try_into_lit(&self) -> Option<LitStr> {\n        Some(self.clone())\n    }\n\n    fn stringify(&self) -> TokenStream {\n        quote_spanned! {self.span()=>\n            ::yew::virtual_dom::AttrValue::Static(#self)\n        }\n    }\n}\n\nimpl Stringify for Lit {\n    fn try_into_lit(&self) -> Option<LitStr> {\n        let mut buf = [0; size_of::<char>()];\n        let s: Cow<'_, str> = match self {\n            Lit::Str(v) => return v.try_into_lit(),\n            Lit::Char(v) => (&*v.value().encode_utf8(&mut buf)).into(),\n            Lit::Int(v) => v.base10_digits().into(),\n            Lit::Float(v) => v.base10_digits().into(),\n            Lit::Bool(v) => if v.value() { \"true\" } else { \"false\" }.into(),\n            Lit::Byte(v) => v.value().to_string().into(),\n            Lit::Verbatim(_) | Lit::ByteStr(_) => return None,\n            _ => unreachable!(\"unknown Lit {:?}\", self),\n        };\n        Some(LitStr::new(&s, self.span()))\n    }\n\n    fn stringify(&self) -> TokenStream {\n        self.try_into_lit()\n            .as_ref()\n            .map_or_else(|| stringify_at_runtime(self), Stringify::stringify)\n    }\n}\n\nimpl Stringify for Expr {\n    fn try_into_lit(&self) -> Option<LitStr> {\n        if let Expr::Lit(v) = self {\n            v.lit.try_into_lit()\n        } else {\n            None\n        }\n    }\n\n    fn stringify(&self) -> TokenStream {\n        self.try_into_lit()\n            .as_ref()\n            .map_or_else(|| stringify_at_runtime(self), Stringify::stringify)\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/use_prepared_state.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::quote;\nuse syn::parse::{Parse, ParseStream};\nuse syn::{Expr, ExprClosure, ReturnType, Token, Type};\n\n#[derive(Debug)]\npub struct PreparedState {\n    closure: ExprClosure,\n    return_type: Type,\n    deps: Expr,\n}\n\nimpl Parse for PreparedState {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        // Reads the deps.\n        let deps = input.parse()?;\n\n        input.parse::<Token![,]>().map_err(|e| {\n            syn::Error::new(\n                e.span(),\n                \"this hook takes 2 arguments but 1 argument was supplied\",\n            )\n        })?;\n\n        // Reads a closure.\n        let expr: Expr = input.parse()?;\n\n        let closure = match expr {\n            Expr::Closure(m) => m,\n            other => return Err(syn::Error::new_spanned(other, \"expected closure\")),\n        };\n\n        let return_type = match &closure.output {\n            ReturnType::Default => {\n                return Err(syn::Error::new_spanned(\n                    &closure,\n                    \"You must specify a return type for this closure. This is used when the \\\n                     closure is omitted from the client side rendering bundle.\",\n                ))\n            }\n            ReturnType::Type(_rarrow, ty) => *ty.to_owned(),\n        };\n\n        if !input.is_empty() {\n            let maybe_trailing_comma = input.lookahead1();\n\n            if !maybe_trailing_comma.peek(Token![,]) {\n                return Err(maybe_trailing_comma.error());\n            }\n        }\n\n        Ok(Self {\n            closure,\n            return_type,\n            deps,\n        })\n    }\n}\n\nimpl PreparedState {\n    // Async closure was not stable, so we rewrite it to closure + async block\n    #[rustversion::before(1.85)]\n    pub fn rewrite_to_closure_with_async_block(&self) -> ExprClosure {\n        use proc_macro2::Span;\n        use syn::parse_quote;\n\n        let async_token = match &self.closure.asyncness {\n            Some(m) => m,\n            None => return self.closure.clone(),\n        };\n\n        // The async block always need to be move so input can be moved into it.\n        let move_token = self\n            .closure\n            .capture\n            .unwrap_or_else(|| Token![move](Span::call_site()));\n        let body = &self.closure.body;\n\n        let inner = parse_quote! {\n            #async_token #move_token {\n                #body\n            }\n        };\n\n        let mut closure = self.closure.clone();\n\n        closure.asyncness = None;\n        // We omit the output type as it's an opaque future type.\n        closure.output = ReturnType::Default;\n\n        closure.body = inner;\n\n        closure.attrs.push(parse_quote! { #[allow(unused_braces)] });\n\n        closure\n    }\n\n    #[rustversion::since(1.85)]\n    pub fn rewrite_to_closure_with_async_block(&self) -> ExprClosure {\n        self.closure.clone()\n    }\n\n    pub fn to_token_stream_with_closure(&self) -> TokenStream {\n        let deps = &self.deps;\n        let rt = &self.return_type;\n        let closure = self.rewrite_to_closure_with_async_block();\n\n        match &self.closure.asyncness {\n            Some(_) => quote! {\n                ::yew::functional::use_prepared_state_with_suspension::<#rt, _, _, _>(#deps, #closure)\n            },\n            None => quote! {\n                ::yew::functional::use_prepared_state::<#rt, _, _>(#deps, #closure)\n            },\n        }\n    }\n\n    // Expose a hook for the client side.\n    //\n    // The closure is stripped from the client side.\n    pub fn to_token_stream_without_closure(&self) -> TokenStream {\n        let deps = &self.deps;\n        let rt = &self.return_type;\n\n        quote! {\n            ::yew::functional::use_prepared_state::<#rt, _>(#deps)\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/src/use_transitive_state.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::quote;\nuse syn::parse::{Parse, ParseStream};\nuse syn::{Expr, ExprClosure, ReturnType, Token, Type};\n\n#[derive(Debug)]\npub struct TransitiveState {\n    closure: ExprClosure,\n    return_type: Type,\n    deps: Expr,\n}\n\nimpl Parse for TransitiveState {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        // Reads the deps.\n        let deps = input.parse()?;\n\n        input.parse::<Token![,]>().map_err(|e| {\n            syn::Error::new(\n                e.span(),\n                \"this hook takes 2 arguments but 1 argument was supplied\",\n            )\n        })?;\n\n        // Reads a closure.\n        let expr: Expr = input.parse()?;\n\n        let closure = match expr {\n            Expr::Closure(m) => m,\n            other => return Err(syn::Error::new_spanned(other, \"expected closure\")),\n        };\n\n        let return_type = match &closure.output {\n            ReturnType::Default => {\n                return Err(syn::Error::new_spanned(\n                    &closure,\n                    \"You must specify a return type for this closure. This is used when the \\\n                     closure is omitted from the client side rendering bundle.\",\n                ))\n            }\n            ReturnType::Type(_rarrow, ty) => *ty.to_owned(),\n        };\n\n        if !input.is_empty() {\n            let maybe_trailing_comma = input.lookahead1();\n\n            if !maybe_trailing_comma.peek(Token![,]) {\n                return Err(maybe_trailing_comma.error());\n            }\n        }\n\n        Ok(Self {\n            closure,\n            return_type,\n            deps,\n        })\n    }\n}\n\nimpl TransitiveState {\n    pub fn to_token_stream_with_closure(&self) -> TokenStream {\n        let deps = &self.deps;\n        let rt = &self.return_type;\n        let closure = &self.closure;\n\n        quote! {\n            ::yew::functional::use_transitive_state::<#rt, _, _>(#deps, #closure)\n        }\n    }\n\n    // Expose a hook for the client side.\n    //\n    // The closure is stripped from the client side.\n    pub fn to_token_stream_without_closure(&self) -> TokenStream {\n        let deps = &self.deps;\n        let rt = &self.return_type;\n\n        quote! {\n            ::yew::functional::use_transitive_state::<#rt, _>(#deps)\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/classes_macro/classes-fail.rs",
    "content": "use yew::prelude::*;\n\nfn compile_pass() {\n    classes!(42);\n    classes!(42.0);\n\n    classes!(\"one\" \"two\");\n\n    classes!(vec![42]);\n\n    let some = Some(42);\n    let none: Option<u32> = None;\n    classes!(some);\n    classes!(none);\n\n    classes!(\"one\", 42);\n\n    classes!(\"one\", \"two three\", \"four\");\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/classes_macro/classes-fail.stderr",
    "content": "error: expected `,`\n --> tests/classes_macro/classes-fail.rs:7:20\n  |\n7 |     classes!(\"one\" \"two\");\n  |                    ^^^^^\n\nerror: string literals must not contain more than one class (hint: use `\"two\", \"three\"`)\n  --> tests/classes_macro/classes-fail.rs:18:21\n   |\n18 |     classes!(\"one\", \"two three\", \"four\");\n   |                     ^^^^^^^^^^^\n\nerror[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied\n --> tests/classes_macro/classes-fail.rs:4:14\n  |\n4 |     classes!(42);\n  |              ^^ the trait `From<{integer}>` is not implemented for `Classes`\n  |\n  = help: the following other types implement trait `From<T>`:\n            `Classes` implements `From<&Classes>`\n            `Classes` implements `From<&Option<T>>`\n            `Classes` implements `From<&String>`\n            `Classes` implements `From<&[T]>`\n            `Classes` implements `From<&implicit_clone::unsync::string::IString>`\n            `Classes` implements `From<&str>`\n            `Classes` implements `From<Cow<'_, str>>`\n            `Classes` implements `From<Option<T>>`\n          and $N others\n  = note: required for `{integer}` to implement `Into<Classes>`\nnote: required by a bound in `Classes::push`\n --> $WORKSPACE/packages/yew/src/html/classes.rs\n  |\n  |     pub fn push<T: Into<Self>>(&mut self, class: T) {\n  |                    ^^^^^^^^^^ required by this bound in `Classes::push`\n\nerror[E0277]: the trait bound `Classes: From<{float}>` is not satisfied\n --> tests/classes_macro/classes-fail.rs:5:14\n  |\n5 |     classes!(42.0);\n  |              ^^^^ the trait `From<{float}>` is not implemented for `Classes`\n  |\n  = help: the following other types implement trait `From<T>`:\n            `Classes` implements `From<&Classes>`\n            `Classes` implements `From<&Option<T>>`\n            `Classes` implements `From<&String>`\n            `Classes` implements `From<&[T]>`\n            `Classes` implements `From<&implicit_clone::unsync::string::IString>`\n            `Classes` implements `From<&str>`\n            `Classes` implements `From<Cow<'_, str>>`\n            `Classes` implements `From<Option<T>>`\n          and $N others\n  = note: required for `{float}` to implement `Into<Classes>`\nnote: required by a bound in `Classes::push`\n --> $WORKSPACE/packages/yew/src/html/classes.rs\n  |\n  |     pub fn push<T: Into<Self>>(&mut self, class: T) {\n  |                    ^^^^^^^^^^ required by this bound in `Classes::push`\n\nerror[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied\n --> tests/classes_macro/classes-fail.rs:9:14\n  |\n9 |     classes!(vec![42]);\n  |              ---^^^^^\n  |              |\n  |              the trait `From<{integer}>` is not implemented for `Classes`\n  |              required by a bound introduced by this call\n  |\n  = help: the following other types implement trait `From<T>`:\n            `Classes` implements `From<&Classes>`\n            `Classes` implements `From<&Option<T>>`\n            `Classes` implements `From<&String>`\n            `Classes` implements `From<&[T]>`\n            `Classes` implements `From<&implicit_clone::unsync::string::IString>`\n            `Classes` implements `From<&str>`\n            `Classes` implements `From<Cow<'_, str>>`\n            `Classes` implements `From<Option<T>>`\n          and $N others\n  = note: required for `{integer}` to implement `Into<Classes>`\n  = note: required for `Classes` to implement `From<Vec<{integer}>>`\n  = note: 1 redundant requirement hidden\n  = note: required for `Vec<{integer}>` to implement `Into<Classes>`\nnote: required by a bound in `Classes::push`\n --> $WORKSPACE/packages/yew/src/html/classes.rs\n  |\n  |     pub fn push<T: Into<Self>>(&mut self, class: T) {\n  |                    ^^^^^^^^^^ required by this bound in `Classes::push`\n\nerror[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied\n  --> tests/classes_macro/classes-fail.rs:13:14\n   |\n13 |     classes!(some);\n   |              ^^^^ the trait `From<{integer}>` is not implemented for `Classes`\n   |\n   = help: the following other types implement trait `From<T>`:\n             `Classes` implements `From<&Classes>`\n             `Classes` implements `From<&Option<T>>`\n             `Classes` implements `From<&String>`\n             `Classes` implements `From<&[T]>`\n             `Classes` implements `From<&implicit_clone::unsync::string::IString>`\n             `Classes` implements `From<&str>`\n             `Classes` implements `From<Cow<'_, str>>`\n             `Classes` implements `From<Option<T>>`\n           and $N others\n   = note: required for `{integer}` to implement `Into<Classes>`\n   = note: required for `Classes` to implement `From<Option<{integer}>>`\n   = note: 1 redundant requirement hidden\n   = note: required for `Option<{integer}>` to implement `Into<Classes>`\nnote: required by a bound in `Classes::push`\n  --> $WORKSPACE/packages/yew/src/html/classes.rs\n   |\n   |     pub fn push<T: Into<Self>>(&mut self, class: T) {\n   |                    ^^^^^^^^^^ required by this bound in `Classes::push`\n\nerror[E0277]: the trait bound `Classes: From<u32>` is not satisfied\n  --> tests/classes_macro/classes-fail.rs:14:14\n   |\n14 |     classes!(none);\n   |              ^^^^ the trait `From<u32>` is not implemented for `Classes`\n   |\n   = help: the following other types implement trait `From<T>`:\n             `Classes` implements `From<&Classes>`\n             `Classes` implements `From<&Option<T>>`\n             `Classes` implements `From<&String>`\n             `Classes` implements `From<&[T]>`\n             `Classes` implements `From<&implicit_clone::unsync::string::IString>`\n             `Classes` implements `From<&str>`\n             `Classes` implements `From<Cow<'_, str>>`\n             `Classes` implements `From<Option<T>>`\n           and $N others\n   = note: required for `u32` to implement `Into<Classes>`\n   = note: required for `Classes` to implement `From<Option<u32>>`\n   = note: 1 redundant requirement hidden\n   = note: required for `Option<u32>` to implement `Into<Classes>`\nnote: required by a bound in `Classes::push`\n  --> $WORKSPACE/packages/yew/src/html/classes.rs\n   |\n   |     pub fn push<T: Into<Self>>(&mut self, class: T) {\n   |                    ^^^^^^^^^^ required by this bound in `Classes::push`\n\nerror[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied\n  --> tests/classes_macro/classes-fail.rs:16:21\n   |\n16 |     classes!(\"one\", 42);\n   |                     ^^ the trait `From<{integer}>` is not implemented for `Classes`\n   |\n   = help: the following other types implement trait `From<T>`:\n             `Classes` implements `From<&Classes>`\n             `Classes` implements `From<&Option<T>>`\n             `Classes` implements `From<&String>`\n             `Classes` implements `From<&[T]>`\n             `Classes` implements `From<&implicit_clone::unsync::string::IString>`\n             `Classes` implements `From<&str>`\n             `Classes` implements `From<Cow<'_, str>>`\n             `Classes` implements `From<Option<T>>`\n           and $N others\n   = note: required for `{integer}` to implement `Into<Classes>`\nnote: required by a bound in `Classes::push`\n  --> $WORKSPACE/packages/yew/src/html/classes.rs\n   |\n   |     pub fn push<T: Into<Self>>(&mut self, class: T) {\n   |                    ^^^^^^^^^^ required by this bound in `Classes::push`\n"
  },
  {
    "path": "packages/yew-macro/tests/classes_macro/classes-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn compile_pass() {\n    // multiple literals\n    ::yew::classes!(\"one\", \"two\");\n    // single literal\n    ::yew::classes!(\"one\");\n    // empty\n    ::yew::classes!();\n\n    // multiple expressions\n    ::yew::classes!(::std::vec![\"one\"], ::std::vec![\"two\"]);\n    // single expression\n    ::yew::classes!(::std::vec![\"one\", \"two\"]);\n\n    // single array\n    ::yew::classes!([\"one\", \"two\"]);\n    // multiple arrays\n    ::yew::classes!([\"one\"], [\"two\"]);\n\n    // optional classes\n    ::yew::classes!(\n        ::std::option::Option::Some(\"one\"),\n        ::std::option::Option::None::<&'static ::std::primitive::str>,\n    );\n\n    // mixed types\n    {\n        use ::std::borrow::ToOwned;\n        ::yew::classes!(\"one\".to_owned(), \"two\", ::std::vec![\"three\"], [\"four\", \"five\"]);\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/classes_macro_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn classes_macro() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/classes_macro/*-pass.rs\");\n    t.compile_fail(\"tests/classes_macro/*-fail.rs\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/derive_props/fail.rs",
    "content": "#![recursion_limit = \"128\"]\n\nuse yew::prelude::*;\n\nmod t1 {\n    use super::*;\n    #[derive(Clone)]\n    struct Value;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: optional params must implement default\n        #[prop_or_default]\n        value: Value,\n    }\n}\n\nmod t2 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: old syntax no longer supported\n        #[props(default)]\n        value: String,\n    }\n}\n\nmod t3 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        value: String,\n    }\n\n    fn required_props_should_be_set() {\n        ::yew::props!{ Props { } };\n    }\n}\n\nmod t4 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        value: Option<String>\n    }\n\n    fn required_option_should_be_provided() {\n        ::yew::props!{ Props { } };\n    }\n}\n\nmod t5 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: prop_or must be given a value\n        #[prop_or()]\n        value: String,\n    }\n}\n\nmod t6 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: 123 is not a String\n        #[prop_or(123)]\n        value: String,\n    }\n}\n\nmod t7 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: 123 is not a function\n        #[prop_or_else(123)]\n        value: i32,\n    }\n}\n\nmod t8 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: cannot find function foo in this scope\n        #[prop_or_else(foo)]\n        value: String,\n    }\n}\n\nmod t9 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: the function must take no arguments\n        #[prop_or_else(foo)]\n        value: String,\n    }\n\n    fn foo(bar: i32) -> String {\n        unimplemented!()\n    }\n}\n\nmod t10 {\n    use super::*;\n    #[derive(Clone, Properties, PartialEq)]\n    pub struct Props {\n        // ERROR: the function returns incompatible types\n        #[prop_or_else(foo)]\n        value: String,\n    }\n\n    fn foo() -> i32 {\n        unimplemented!()\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/derive_props/fail.stderr",
    "content": "error: unexpected end of input, expected an expression\n  --> tests/derive_props/fail.rs:56:19\n   |\n56 |         #[prop_or()]\n   |                   ^\n\nerror: cannot find attribute `props` in this scope\n  --> tests/derive_props/fail.rs:22:11\n   |\n22 |         #[props(default)]\n   |           ^^^^^\n\nerror[E0425]: cannot find value `foo` in this scope\n   --> tests/derive_props/fail.rs:86:24\n    |\n86  |         #[prop_or_else(foo)]\n    |                        ^^^ not found in this scope\n    |\nnote: these functions exist but are inaccessible\n   --> tests/derive_props/fail.rs:100:5\n    |\n100 |     fn foo(bar: i32) -> String {\n    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `crate::t9::foo`: not accessible\n...\n114 |     fn foo() -> i32 {\n    |     ^^^^^^^^^^^^^^^ `crate::t10::foo`: not accessible\n\nerror[E0277]: the trait bound `Value: Default` is not satisfied\n --> tests/derive_props/fail.rs:9:21\n  |\n9 |     #[derive(Clone, Properties, PartialEq)]\n  |                     ^^^^^^^^^^ the trait `Default` is not implemented for `Value`\n  |\nnote: required by a bound in `Option::<T>::unwrap_or_default`\n --> $RUST/core/src/option.rs\n  = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\nhelp: consider annotating `Value` with `#[derive(Default)]`\n  |\n8 +     #[derive(Default)]\n9 |     struct Value;\n  |\n\nerror[E0369]: binary operation `==` cannot be applied to type `Value`\n  --> tests/derive_props/fail.rs:13:9\n   |\n9  |     #[derive(Clone, Properties, PartialEq)]\n   |                                 --------- in this derive macro expansion\n...\n13 |         value: Value,\n   |         ^^^^^^^^^^^^\n   |\nnote: an implementation of `PartialEq` might be missing for `Value`\n  --> tests/derive_props/fail.rs:8:5\n   |\n8  |     struct Value;\n   |     ^^^^^^^^^^^^ must implement `PartialEq`\n   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)\nhelp: consider annotating `Value` with `#[derive(PartialEq)]`\n   |\n8  +     #[derive(PartialEq)]\n9  |     struct Value;\n   |\n\nerror[E0277]: not all required properties have been provided\n  --> tests/derive_props/fail.rs:35:24\n   |\n35 |         ::yew::props!{ Props { } };\n   |                        ^^^^^ missing required properties for this component\n   |\n   = help: the trait `HasProp<t3::_Props::value, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<children, HasContextProviderPropschildren<B>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<yew::context::_ContextProviderProps::context, HasContextProviderPropscontext<B>>`\n             `suspense::component::CheckSuspensePropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `t10::CheckPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `t3::CheckPropsAll<AssertAllProps>` to implement `HasAllProps<t3::Props, (_,)>`\n  --> tests/derive_props/fail.rs:29:21\n   |\n29 |     #[derive(Clone, Properties, PartialEq)]\n   |                     ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `AssertAllProps` to implement `AllPropsFor<t3::PropsBuilder, (_,)>`\nnote: required by a bound in `html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: not all required properties have been provided\n  --> tests/derive_props/fail.rs:47:24\n   |\n47 |         ::yew::props!{ Props { } };\n   |                        ^^^^^ missing required properties for this component\n   |\n   = help: the trait `HasProp<t4::_Props::value, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<children, HasContextProviderPropschildren<B>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<yew::context::_ContextProviderProps::context, HasContextProviderPropscontext<B>>`\n             `suspense::component::CheckSuspensePropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `t10::CheckPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `t4::CheckPropsAll<AssertAllProps>` to implement `HasAllProps<t4::Props, (_,)>`\n  --> tests/derive_props/fail.rs:41:21\n   |\n41 |     #[derive(Clone, Properties, PartialEq)]\n   |                     ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `AssertAllProps` to implement `AllPropsFor<t4::PropsBuilder, (_,)>`\nnote: required by a bound in `html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0308]: mismatched types\n  --> tests/derive_props/fail.rs:66:19\n   |\n66 |         #[prop_or(123)]\n   |                   ^^^- help: try using a conversion method: `.to_string()`\n   |                   |\n   |                   expected `String`, found integer\n   |                   arguments to this function are incorrect\n   |\nnote: method defined here\n  --> $RUST/core/src/option.rs\n\nerror[E0277]: expected a `FnOnce()` closure, found `{integer}`\n  --> tests/derive_props/fail.rs:76:24\n   |\n76 |         #[prop_or_else(123)]\n   |                        ^^^ expected an `FnOnce()` closure, found `{integer}`\n   |\n   = help: the trait `FnOnce()` is not implemented for `{integer}`\n   = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`\nnote: required by a bound in `Option::<T>::unwrap_or_else`\n  --> $RUST/core/src/option.rs\n\nerror[E0593]: function is expected to take 0 arguments, but it takes 1 argument\n   --> tests/derive_props/fail.rs:96:24\n    |\n96  |         #[prop_or_else(foo)]\n    |                        ^^^ expected function that takes 0 arguments\n...\n100 |     fn foo(bar: i32) -> String {\n    |     -------------------------- takes 1 argument\n    |\nnote: required by a bound in `Option::<T>::unwrap_or_else`\n   --> $RUST/core/src/option.rs\n\nerror[E0271]: expected `foo` to be a fn item that returns `String`, but it returns `i32`\n   --> tests/derive_props/fail.rs:110:24\n    |\n110 |         #[prop_or_else(foo)]\n    |                        ^^^ expected `String`, found `i32`\n    |\nnote: required by a bound in `Option::<T>::unwrap_or_else`\n   --> $RUST/core/src/option.rs\n\nwarning: unused variable: `bar`\n   --> tests/derive_props/fail.rs:100:12\n    |\n100 |     fn foo(bar: i32) -> String {\n    |            ^^^ help: if this is intentional, prefix it with an underscore: `_bar`\n    |\n    = note: `#[warn(unused_variables)]` on by default\n"
  },
  {
    "path": "packages/yew-macro/tests/derive_props/pass.rs",
    "content": "#![recursion_limit = \"128\"]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nmod t1 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props<T: ::std::clone::Clone + ::std::default::Default + ::std::cmp::PartialEq> {\n        #[prop_or_default]\n        value: T,\n    }\n\n    fn optional_prop_generics_should_work() {\n        ::yew::props! { Props::<::std::primitive::bool> { } };\n        ::yew::props! { Props::<::std::primitive::bool> { value: true } };\n    }\n}\n\nmod t2 {\n    #[derive(::std::clone::Clone, ::std::cmp::PartialEq)]\n    struct Value;\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props<T: ::std::clone::Clone + ::std::cmp::PartialEq> {\n        value: T,\n    }\n\n    fn required_prop_generics_should_work() {\n        ::yew::props! { Props::<Value> { value: Value } };\n    }\n}\n\nmod t3 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props {\n        b: ::std::primitive::i32,\n        #[prop_or_default]\n        a: ::std::primitive::i32,\n    }\n\n    fn order_is_alphabetized() {\n        ::yew::props! { Props { b: 1 } };\n        ::yew::props! { Props { a: 1, b: 2 } };\n    }\n}\n\nmod t4 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props<T>\n    where\n        T: ::std::clone::Clone + ::std::default::Default + ::std::cmp::PartialEq,\n    {\n        #[prop_or_default]\n        value: T,\n    }\n\n    fn optional_prop_generics_should_work() {\n        ::yew::props! { Props::<::std::primitive::bool> { } };\n        ::yew::props! { Props::<::std::primitive::bool> { value: true } };\n    }\n}\n\nmod t5 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props<\n        'a,\n        T: ::std::clone::Clone + ::std::default::Default + ::std::cmp::PartialEq + 'a,\n    > {\n        #[prop_or_default]\n        static_value: &'static ::std::primitive::str,\n        value: &'a T,\n    }\n\n    fn optional_prop_generics_with_lifetime_should_work() {\n        use ::std::{convert::From, string::String};\n\n        let borrowed_value = &String::from(\"\");\n        ::yew::props! { Props::<String> { value: borrowed_value, } };\n        ::yew::props! { Props::<String> { static_value: \"\", value: borrowed_value, } };\n    }\n}\n\nmod t6 {\n    #[derive(::yew::Properties, ::std::clone::Clone, ::std::cmp::PartialEq)]\n    pub struct Props<T: ::std::str::FromStr + ::std::clone::Clone + ::std::cmp::PartialEq>\n    where\n        <T as ::std::str::FromStr>::Err: ::std::clone::Clone + ::std::cmp::PartialEq,\n    {\n        value: ::std::result::Result<T, <T as ::std::str::FromStr>::Err>,\n    }\n\n    fn required_prop_generics_with_where_clause_should_work() {\n        use ::std::{convert::From, result::Result::Ok, string::String};\n\n        ::yew::props! { Props::<String> { value: Ok(String::from(\"\")) } };\n    }\n}\n\nmod t7 {\n    #[derive(::std::clone::Clone, Debug, Eq, ::std::cmp::PartialEq)]\n    pub enum Foo {\n        One,\n        Two,\n    }\n\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props {\n        #[prop_or(Foo::One)]\n        value: Foo,\n    }\n\n    fn prop_or_value_should_work() {\n        use ::std::assert_eq;\n\n        let props = ::yew::props! { Props { } };\n        assert_eq!(props.value, Foo::One);\n        ::yew::props! { Props { value: Foo::Two } };\n    }\n}\n\nmod t8 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props {\n        #[prop_or_else(|| 123)]\n        value: ::std::primitive::i32,\n    }\n\n    fn prop_or_else_closure_should_work() {\n        use ::std::assert_eq;\n\n        let props = ::yew::props! { Props { } };\n        assert_eq!(props.value, 123);\n        ::yew::props! { Props { value: 123 } };\n    }\n}\n\nmod t9 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props<T: ::std::str::FromStr + ::std::clone::Clone + ::std::cmp::PartialEq>\n    where\n        <T as ::std::str::FromStr>::Err: ::std::clone::Clone + ::std::cmp::PartialEq,\n    {\n        #[prop_or_else(default_value)]\n        value: ::std::result::Result<T, <T as ::std::str::FromStr>::Err>,\n    }\n\n    fn default_value<T: ::std::str::FromStr + ::std::clone::Clone>(\n    ) -> ::std::result::Result<T, <T as ::std::str::FromStr>::Err>\n    where\n        <T as ::std::str::FromStr>::Err: ::std::clone::Clone,\n    {\n        \"123\".parse()\n    }\n\n    fn prop_or_else_function_with_generics_should_work() {\n        use ::std::{assert_eq, result::Result::Ok};\n\n        let props = ::yew::props! { Props::<::std::primitive::i32> { } };\n        assert_eq!(props.value, Ok(123));\n        ::yew::props! { Props::<::std::primitive::i32> { value: Ok(456) } };\n    }\n}\n\nmod t10 {\n    // this test makes sure that Yew handles generic params with default values properly.\n\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Foo<S, M = S>\n    where\n        S: ::std::clone::Clone + ::std::cmp::PartialEq,\n        M: ::std::clone::Clone + ::std::cmp::PartialEq,\n    {\n        bar: S,\n        baz: M,\n    }\n}\n\nmod t11 {\n    // this test makes sure that Yew handles generic params with const generics properly.\n\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Foo<T, const N: usize>\n    where\n        T: ::std::clone::Clone + ::std::cmp::PartialEq,\n    {\n        bar: [T; N],\n    }\n}\n\nmod t12 {\n    #[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props<T: ::std::clone::Clone + ::std::cmp::PartialEq> {\n        value: ::std::option::Option<T>,\n    }\n\n    fn optional_prop_generics_should_work() {\n        ::yew::props! { Props::<::std::primitive::bool> { value: ::std::option::Option::Some(true) } };\n        ::yew::props! { Props::<::std::primitive::bool> { value: true } };\n    }\n}\n\n#[deny(non_snake_case, dead_code)]\nmod t13 {\n    #[derive(::std::cmp::PartialEq, ::yew::Properties)]\n    #[allow(non_snake_case)] // putting this on fields directly does not work, even in normal rust\n    struct Props {\n        #[allow(dead_code)]\n        create_message: ::std::option::Option<bool>,\n        NonSnakeCase: u32,\n    }\n}\n\nmod raw_field_names {\n    #[derive(::yew::Properties, ::std::cmp::PartialEq)]\n    pub struct Props {\n        r#true: u32,\n        r#pointless_raw_name: u32,\n    }\n}\n\nmod value_into_some_value_in_props {\n    #[derive(::std::cmp::PartialEq, ::yew::Properties)]\n    struct Props {\n        required: ::std::option::Option<usize>,\n        #[prop_or_default]\n        optional: ::std::option::Option<usize>\n    }\n\n    #[::yew::component]\n    fn Inner(_props: &Props) -> ::yew::html::Html {\n        ::yew::html!{}\n    }\n\n    #[::yew::component]\n    fn Main() -> ::yew::html::Html {\n        ::yew::html! {<>\n            <Inner required=3 optional=5/>\n            <Inner required={::std::option::Option::Some(6)}/>\n        </>}\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/derive_props_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn derive_props() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/derive_props/pass.rs\");\n    t.compile_fail(\"tests/derive_props/fail.rs\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_attr_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn tests() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/function_component_attr/*-pass.rs\");\n    t.compile_fail(\"tests/function_component_attr/*-fail.rs\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/applied-to-non-fn-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nstruct Test;\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/applied-to-non-fn-fail.stderr",
    "content": "error: `component` attribute can only be applied to functions\n --> $DIR/applied-to-non-fn-fail.rs:9:1\n  |\n9 | struct Test;\n  | ^^^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/async-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nasync fn comp(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/async-fail.stderr",
    "content": "error: function components can't be async\n --> $DIR/async-fail.rs:9:1\n  |\n9 | async fn comp(props: &Props) -> Html {\n  | ^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/bad-name-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(let)]\nfn comp(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\n#[component(x, y, z)]\nfn comp_2(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\n#[component(124)]\nfn comp_3(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\n#[component(component)]\nfn component(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/bad-name-fail.stderr",
    "content": "error: expected identifier, found keyword `let`\n --> tests/function_component_attr/bad-name-fail.rs:8:13\n  |\n8 | #[component(let)]\n  |             ^^^\n\nerror: unexpected token\n  --> tests/function_component_attr/bad-name-fail.rs:17:14\n   |\n17 | #[component(x, y, z)]\n   |              ^\n\nerror: expected identifier\n  --> tests/function_component_attr/bad-name-fail.rs:26:13\n   |\n26 | #[component(124)]\n   |             ^^^\n\nerror: the component must not have the same name as the function\n  --> tests/function_component_attr/bad-name-fail.rs:35:13\n   |\n35 | #[component(component)]\n   |             ^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/bad-props-param-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nfn comp(props: Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/bad-props-param-fail.stderr",
    "content": "error: expected a reference to a `Properties` type (try: `&Props`)\n --> $DIR/bad-props-param-fail.rs:9:16\n  |\n9 | fn comp(props: Props) -> Html {\n  |                ^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/bad-return-type-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp1)]\nfn comp_1(_props: &Props) {}\n\n#[component(Comp)]\nfn comp(_props: &Props) -> u32 {\n    1\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/bad-return-type-fail.stderr",
    "content": "error: function components must return `yew::Html` or `yew::HtmlResult`\n --> tests/function_component_attr/bad-return-type-fail.rs:9:1\n  |\n9 | fn comp_1(_props: &Props) {}\n  | ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nerror[E0277]: the trait bound `u32: IntoHtmlResult` is not satisfied\n  --> tests/function_component_attr/bad-return-type-fail.rs:11:1\n   |\n11 | #[component(Comp)]\n   | ^^^^^^^^^^^^^^^^^^ the trait `IntoHtmlResult` is not implemented for `u32`\n   |\n   = help: the following other types implement trait `IntoHtmlResult`:\n             Result<VNode, RenderError>\n             VNode\n   = note: this error originates in the attribute macro `component` (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/const-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nconst fn comp(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/const-fail.stderr",
    "content": "error: const functions can't be function components\n --> $DIR/const-fail.rs:9:1\n  |\n9 | const fn comp(props: &Props) -> Html {\n  | ^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/extern-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nextern \"C\" fn comp(props: &Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/extern-fail.stderr",
    "content": "error: extern functions can't be function components\n --> $DIR/extern-fail.rs:9:1\n  |\n9 | extern \"C\" fn comp(props: &Props) -> Html {\n  | ^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/generic-lifetime-fail.rs",
    "content": "use yew::prelude::*;\r\n\r\n#[derive(Clone, Properties, PartialEq)]\r\nstruct Props {\r\n    a: usize,\r\n}\r\n\r\n#[component(Comp)]\r\nfn comp<'a>(props: &'a Props) -> Html {\r\n    html! {\r\n        <p>\r\n            { props.a }\r\n        </p>\r\n    }\r\n}\r\n\r\nfn main() {}\r\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/generic-lifetime-fail.stderr",
    "content": "error: function components can't have generic lifetime parameters\n --> $DIR/generic-lifetime-fail.rs:9:8\n  |\n9 | fn comp<'a>(props: &'a Props) -> Html {\n  |        ^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/generic-pass.rs",
    "content": "\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\nstruct Props {\n    a: ::std::primitive::usize,\n}\n\n#[::yew::component(Comp)]\nfn comp<P>(_props: &P) -> ::yew::Html\nwhere\n    P: ::yew::Properties + ::std::cmp::PartialEq,\n{\n    ::yew::html! {\n        <p></p>\n    }\n}\n\n#[::yew::component(Comp1)]\nfn comp1<T1, T2>(_props: &()) -> ::yew::Html {\n    ::yew::html! {\n        <p></p>\n    }\n}\n\n#[::yew::component(ConstGenerics)]\nfn const_generics<const N: ::std::primitive::i32>() -> ::yew::Html {\n    ::yew::html! {\n        <div>\n            { N }\n        </div>\n    }\n}\n\nfn compile_pass() {\n    let _ = ::yew::html! { <Comp<Props> a=10 /> };\n    let _ = ::yew::html! { <Comp1<::std::primitive::usize, ::std::primitive::usize> /> };\n\n    let _ = ::yew::html! { <ConstGenerics<10> /> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/generic-props-fail.rs",
    "content": "use yew::prelude::*;\r\n\r\n#[derive(Clone, Properties, PartialEq)]\r\nstruct Props {\r\n    a: usize,\r\n}\r\n\r\n#[component(Comp)]\r\nfn comp<P>(_props: &P) -> Html\r\nwhere\r\n    P: Properties + PartialEq,\r\n{\r\n    html! {\r\n        <p></p>\r\n    }\r\n}\r\n\r\nstruct MissingTypeBounds;\r\n\r\nfn compile_fail() {\r\n    // missing prop 'a'\r\n    html! { <Comp<Props> /> };\r\n\r\n    // invalid type parameter\r\n    html! { <Comp<INVALID> /> };\r\n    // parameter doesn't match bounds\r\n    html! { <Comp<MissingTypeBounds> /> };\r\n\r\n    // missing type param\r\n    html! { <Comp /> };\r\n}\r\n\r\nfn main() {}\r\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/generic-props-fail.stderr",
    "content": "error[E0412]: cannot find type `INVALID` in this scope\n  --> tests/function_component_attr/generic-props-fail.rs:25:19\n   |\n25 |     html! { <Comp<INVALID> /> };\n   |                   ^^^^^^^ not found in this scope\n   |\nhelp: you might be missing a type parameter\n   |\n20 | fn compile_fail<INVALID>() {\n   |                +++++++++\n\nerror[E0277]: not all required properties have been provided\n  --> tests/function_component_attr/generic-props-fail.rs:22:14\n   |\n22 |     html! { <Comp<Props> /> };\n   |              ^^^^ missing required properties for this component\n   |\n   = help: the trait `HasProp<a, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<children, HasContextProviderPropschildren<B>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<yew::context::_ContextProviderProps::context, HasContextProviderPropscontext<B>>`\n             `HasPropsa<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `CheckPropsAll<AssertAllProps>` to implement `HasAllProps<Props, (_,)>`\n  --> tests/function_component_attr/generic-props-fail.rs:3:17\n   |\n3  | #[derive(Clone, Properties, PartialEq)]\n   |                 ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `AssertAllProps` to implement `AllPropsFor<PropsBuilder, (_,)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `Comp<MissingTypeBounds>: yew::BaseComponent` is not satisfied\n  --> tests/function_component_attr/generic-props-fail.rs:27:14\n   |\n27 |     html! { <Comp<MissingTypeBounds> /> };\n   |              ^^^^^^^^^^^^^^^^^^^^^^^ the trait `yew::BaseComponent` is not implemented for `Comp<MissingTypeBounds>`\n   |\n   = help: the trait `yew::BaseComponent` is implemented for `Comp<P>`\n\nerror[E0277]: the trait bound `MissingTypeBounds: yew::Properties` is not satisfied\n  --> tests/function_component_attr/generic-props-fail.rs:27:14\n   |\n27 |     html! { <Comp<MissingTypeBounds> /> };\n   |              ^^^^ the trait `yew::Properties` is not implemented for `MissingTypeBounds`\n   |\n   = help: the following other types implement trait `yew::Properties`:\n             ()\n             ChildrenProps\n             ContextProviderProps<T>\n             Props\n             SuspenseProps\nnote: required by a bound in `Comp`\n  --> tests/function_component_attr/generic-props-fail.rs:11:8\n   |\n8  | #[component(Comp)]\n   |             ---- required by a bound in this struct\n...\n11 |     P: Properties + PartialEq,\n   |        ^^^^^^^^^^ required by this bound in `Comp`\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0599]: the function or associated item `new` exists for struct `VChild<Comp<MissingTypeBounds>>`, but its trait bounds were not satisfied\n  --> tests/function_component_attr/generic-props-fail.rs:27:14\n   |\n8  | #[component(Comp)]\n   | ---------------- doesn't satisfy `Comp<MissingTypeBounds>: yew::BaseComponent`\n...\n27 |     html! { <Comp<MissingTypeBounds> /> };\n   |              ^^^^ function or associated item cannot be called on `VChild<Comp<MissingTypeBounds>>` due to unsatisfied trait bounds\n   |\n   = note: the following trait bounds were not satisfied:\n           `Comp<MissingTypeBounds>: yew::BaseComponent`\nnote: the trait `yew::BaseComponent` must be implemented\n  --> $WORKSPACE/packages/yew/src/html/component/mod.rs\n   |\n   | pub trait BaseComponent: Sized + 'static {\n   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `Comp<MissingTypeBounds>: yew::BaseComponent` is not satisfied\n  --> tests/function_component_attr/generic-props-fail.rs:27:14\n   |\n27 |     html! { <Comp<MissingTypeBounds> /> };\n   |              ^^^^ the trait `yew::BaseComponent` is not implemented for `Comp<MissingTypeBounds>`\n   |\n   = help: the trait `yew::BaseComponent` is implemented for `Comp<P>`\nnote: required by a bound in `VChild`\n  --> $WORKSPACE/packages/yew/src/virtual_dom/vcomp.rs\n   |\n   | pub struct VChild<COMP: BaseComponent> {\n   |                         ^^^^^^^^^^^^^ required by this bound in `VChild`\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0107]: missing generics for struct `Comp`\n  --> tests/function_component_attr/generic-props-fail.rs:30:14\n   |\n30 |     html! { <Comp /> };\n   |              ^^^^ expected 1 generic argument\n   |\nnote: struct defined here, with 1 generic parameter: `P`\n  --> tests/function_component_attr/generic-props-fail.rs:8:13\n   |\n8  | #[component(Comp)]\n   |             ^^^^\n9  | fn comp<P>(_props: &P) -> Html\n   |         -\nhelp: add missing generic argument\n   |\n30 |     html! { <Comp<P> /> };\n   |                  +++\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/hook_location-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Debug, PartialEq, Clone)]\nstruct Ctx;\n\n#[component]\nfn Comp() -> Html {\n    if let Some(_m) = use_context::<Ctx>() {\n        use_context::<Ctx>().unwrap();\n        todo!()\n    }\n\n    let _ = || {\n        use_context::<Ctx>().unwrap();\n        todo!()\n    };\n\n    for _ in 0..10 {\n        use_context::<Ctx>().unwrap();\n    }\n\n    while let Some(_m) = use_context::<Ctx>() {\n        use_context::<Ctx>().unwrap();\n    }\n\n    match use_context::<Ctx>() {\n        Some(_) => use_context::<Ctx>(),\n        None => {\n            todo!()\n        }\n    }\n\n    loop {\n        use_context::<Ctx>().unwrap();\n        todo!()\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/hook_location-fail.stderr",
    "content": "error: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n --> tests/function_component_attr/hook_location-fail.rs:9:9\n  |\n9 |         use_context::<Ctx>().unwrap();\n  |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/function_component_attr/hook_location-fail.rs:14:9\n   |\n14 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/function_component_attr/hook_location-fail.rs:19:9\n   |\n19 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/function_component_attr/hook_location-fail.rs:22:26\n   |\n22 |     while let Some(_m) = use_context::<Ctx>() {\n   |                          ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/function_component_attr/hook_location-fail.rs:23:9\n   |\n23 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/function_component_attr/hook_location-fail.rs:27:20\n   |\n27 |         Some(_) => use_context::<Ctx>(),\n   |                    ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/function_component_attr/hook_location-fail.rs:34:9\n   |\n34 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/hook_location-pass.rs",
    "content": "\n#[derive(\n    ::std::prelude::rust_2021::Debug,\n    ::std::prelude::rust_2021::PartialEq,\n    ::std::prelude::rust_2021::Clone,\n)]\nstruct Ctx;\n\n#[::yew::prelude::component]\nfn Comp() -> ::yew::prelude::Html {\n    ::yew::prelude::use_context::<Ctx>().unwrap();\n\n    if let ::std::prelude::rust_2021::Some(_m) = ::yew::prelude::use_context::<Ctx>() {\n        ::std::todo!()\n    }\n\n    let _ctx = { ::yew::prelude::use_context::<Ctx>() };\n\n    match ::yew::prelude::use_context::<Ctx>() {\n        ::std::prelude::rust_2021::Some(_) => {\n            ::std::todo!()\n        }\n        ::std::prelude::rust_2021::None => {\n            ::std::todo!()\n        }\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/lifetime-props-param-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nfn comp(props: &'static Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/lifetime-props-param-fail.stderr",
    "content": "error: reference must not have a lifetime\n --> $DIR/lifetime-props-param-fail.rs:9:17\n  |\n9 | fn comp(props: &'static Props) -> Html {\n  |                 ^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/multiple-param-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nfn comp(props: &Props, invalid: String) -> Html {\n    html! {\n        <p>\n            { props.a }\n            { invalid }\n        </p>\n    }\n}\n\n#[component(Comp)]\nfn comp3(props: &Props, invalid: String, another_invalid: u32) -> Html {\n    html! {\n        <p>\n            { props.a }\n            { invalid }\n            { another_invalid }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/multiple-param-fail.stderr",
    "content": "error: function components can accept at most one parameter for the props\n --> $DIR/multiple-param-fail.rs:9:24\n  |\n9 | fn comp(props: &Props, invalid: String) -> Html {\n  |                        ^^^^^^^^^^^^^^^\n\nerror: function components can accept at most one parameter for the props\n  --> $DIR/multiple-param-fail.rs:19:25\n   |\n19 | fn comp3(props: &Props, invalid: String, another_invalid: u32) -> Html {\n   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/mut-ref-props-param-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\n#[component(Comp)]\nfn comp(props: &mut Props) -> Html {\n    html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/mut-ref-props-param-fail.stderr",
    "content": "error: reference must not be mutable\n --> $DIR/mut-ref-props-param-fail.rs:9:17\n  |\n9 | fn comp(props: &mut Props) -> Html {\n  |                 ^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/no-name-default-pass.rs",
    "content": "\n#[derive(::yew::prelude::Properties, ::std::prelude::rust_2021::PartialEq,)]\nstruct Props {\n    a: usize,\n}\n\n#[::yew::prelude::component]\nfn Comp(props: &Props) -> ::yew::prelude::Html {\n    ::yew::prelude::html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {\n    let _ = ::yew::prelude::html! {\n        <Comp a={0} />\n    };\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/with-defaulted-type-param-pass.rs",
    "content": "\n#[derive(::yew::prelude::Properties, ::std::fmt::Debug)]\npub struct CompProps<A> {\n    #[prop_or_default]\n    _phantom: ::std::marker::PhantomData<A>,\n}\n\nimpl<A> ::std::cmp::PartialEq for CompProps<A> {\n    fn eq(&self, _rhs: &Self) -> bool {\n        true\n    }\n}\n\n#[::yew::prelude::component(Comp)]\npub fn comp<A = ()>(_props: &CompProps<A>) -> ::yew::prelude::Html {\n    ::std::todo!()\n}\n\n#[::yew::prelude::component(App)]\npub fn app() -> ::yew::prelude::Html {\n    ::yew::prelude::html! { <Comp /> } // No generics here.\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/with-props-pass.rs",
    "content": "// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[derive(Clone, ::yew::Properties, PartialEq)]\nstruct Props {\n    a: ::std::primitive::usize,\n}\n\n#[::yew::component(Comp)]\nfn comp(props: &Props) -> ::yew::Html {\n    ::yew::html! {\n        <p>\n            { props.a }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/with-receiver-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\nstruct Test;\n\nimpl Test {\n    #[component(Comp)]\n    fn comp(self, props: &Props) -> Html {\n        html! {\n            <p>\n                { props.a }\n            </p>\n        }\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/with-receiver-fail.stderr",
    "content": "error: function components can't accept a receiver\n  --> $DIR/with-receiver-fail.rs:12:13\n   |\n12 |     fn comp(self, props: &Props) -> Html {\n   |             ^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/function_component_attr/without-props-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[::yew::component(Comp)]\nfn comp() -> ::yew::Html {\n    ::yew::html! {\n        <p>\n            { \"Test\" }\n        </p>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-call-generics-pass.rs",
    "content": "use yew::prelude::*;\n\n#[hook]\nfn use_reducer_default_action<T>() -> T::Action\nwhere\n    T: Reducible + 'static,\n    T::Action: Default + 'static,\n{\n    T::Action::default()\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-const-generic-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[::yew::prelude::hook]\nfn use_a_const<const N: u32>() -> u32 {\n    N\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-dynamic-dispatch-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[::yew::prelude::hook]\nfn use_boxed_fn(_f: ::std::boxed::Box<dyn::std::ops::Fn(&str) -> &str>) {\n    ::std::todo!()\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-impl-trait-pass.rs",
    "content": "// we need to re-test the macro hygiene here as it uses a different implementation for impl traits.\n#![no_implicit_prelude]\n\n#[::yew::prelude::hook]\nfn use_some_string(a: impl ::std::convert::Into<::std::string::String>) -> ::std::string::String {\n    a.into()\n}\n\n#[::yew::prelude::hook]\nfn use_impl_fn<T, U>(_callback: impl ::std::prelude::rust_2021::Fn(&T) -> &U) {}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-lifetime-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[::yew::functional::hook]\nfn use_as_is<'a>(input: &'a ()) -> &'a () {\n    input\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-must-use-fail.rs",
    "content": "#![deny(unused_must_use)]\n\nuse yew::prelude::*;\n\nfn not_a_hook() {\n    use_effect_with((), |_| {});\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-must-use-fail.stderr",
    "content": "error: unused implementer of `Hook` that must be used\n --> tests/hook_attr/hook-must-use-fail.rs:6:5\n  |\n6 |     use_effect_with((), |_| {});\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: hooks do nothing unless called inside a `#[hook]` or `#[component]` function\nnote: the lint level is defined here\n --> tests/hook_attr/hook-must-use-fail.rs:1:9\n  |\n1 | #![deny(unused_must_use)]\n  |         ^^^^^^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-must-use-pass.rs",
    "content": "#![deny(unused_must_use)]\n\nuse yew::prelude::*;\n\n#[hook]\nfn use_my_effect() {\n    use_effect_with((), |_| {});\n}\n\n#[component]\nfn Comp() -> Html {\n    use_effect_with((), |_| {});\n    use_my_effect();\n    html! {}\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-return-impl-trait-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[::yew::prelude::hook]\nfn use_deref_as_u32() -> impl ::std::ops::Deref<Target = ::std::primitive::u32> {\n    ::std::rc::Rc::new(0)\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-return-ref-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[::yew::prelude::hook]\nfn use_str_ref(f: &::std::primitive::str) -> &::std::primitive::str {\n    f\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook-trait-item-pass.rs",
    "content": "use std::marker::PhantomData;\n\npub struct QueryState<T> {\n    p: PhantomData<T>\n}\n\npub trait MyTrait {\n    type Associated;\n}\n\n\n#[yew::hook]\npub fn use_query_state<Props>(\n    _selector: impl yew::html::IntoPropValue<bool>,\n) -> QueryState<Props::Associated>\nwhere\n    Props: MyTrait,\n{\n    QueryState::<Props::Associated> { p: PhantomData::<Props::Associated> }\n}\n\nfn main() {}"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook_location-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Debug, PartialEq, Clone)]\nstruct Ctx;\n\n#[hook]\nfn use_some_html() -> Html {\n    if let Some(_m) = use_context::<Ctx>() {\n        use_context::<Ctx>().unwrap();\n        todo!()\n    }\n\n    let _ = || {\n        use_context::<Ctx>().unwrap();\n        todo!()\n    };\n\n    for _ in 0..10 {\n        use_context::<Ctx>().unwrap();\n    }\n\n    while let Some(_m) = use_context::<Ctx>() {\n        use_context::<Ctx>().unwrap();\n    }\n\n    match use_context::<Ctx>() {\n        Some(_) => use_context::<Ctx>(),\n        None => {\n            todo!()\n        }\n    }\n\n    loop {\n        use_context::<Ctx>().unwrap();\n        todo!()\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook_location-fail.stderr",
    "content": "error: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n --> tests/hook_attr/hook_location-fail.rs:9:9\n  |\n9 |         use_context::<Ctx>().unwrap();\n  |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_location-fail.rs:14:9\n   |\n14 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_location-fail.rs:19:9\n   |\n19 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_location-fail.rs:22:26\n   |\n22 |     while let Some(_m) = use_context::<Ctx>() {\n   |                          ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_location-fail.rs:23:9\n   |\n23 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_location-fail.rs:27:20\n   |\n27 |         Some(_) => use_context::<Ctx>(),\n   |                    ^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_location-fail.rs:34:9\n   |\n34 |         use_context::<Ctx>().unwrap();\n   |         ^^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook_location-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[derive(\n    ::std::prelude::rust_2021::Debug,\n    ::std::prelude::rust_2021::PartialEq,\n    ::std::prelude::rust_2021::Clone,\n)]\nstruct Ctx;\n\n#[::yew::prelude::hook]\nfn use_some_html() -> ::yew::prelude::Html {\n    ::yew::prelude::use_context::<Ctx>().unwrap();\n\n    if let ::std::prelude::rust_2021::Some(_m) = ::yew::prelude::use_context::<Ctx>() {\n        ::std::todo!()\n    }\n\n    let _ctx = { ::yew::prelude::use_context::<Ctx>() };\n\n    match ::yew::prelude::use_context::<Ctx>() {\n        ::std::prelude::rust_2021::Some(_) => {\n            ::std::todo!()\n        }\n        ::std::prelude::rust_2021::None => {\n            ::std::todo!()\n        }\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook_macro-fail.rs",
    "content": "use yew::prelude::*;\n\n#[hook]\npub fn use_some_macro_inner(val: &str) -> String {\n    use_state(|| val.to_owned()).to_string()\n}\n\nmacro_rules! use_some_macro {\n    () => {\n        use_some_macro_inner(\"default str\")\n    };\n    ($t: tt) => {\n        use_some_macro_inner($t)\n    };\n}\n\n#[component]\nfn Comp() -> Html {\n    let content = if true {\n        use_some_macro!()\n    } else {\n        use_some_macro!(\"b\")\n    };\n\n    html! {\n        <div>{content}</div>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook_macro-fail.stderr",
    "content": "error: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_macro-fail.rs:20:9\n   |\n20 |         use_some_macro!()\n   |         ^^^^^^^^^^^^^^\n\nerror: hooks cannot be called at this position.\n\n         = help: move hooks to the top-level of your function.\n         = note: see: https://yew.rs/docs/next/concepts/function-components/hooks\n\n  --> tests/hook_attr/hook_macro-fail.rs:22:9\n   |\n22 |         use_some_macro!(\"b\")\n   |         ^^^^^^^^^^^^^^\n\nwarning: unused macro definition: `use_some_macro`\n --> tests/hook_attr/hook_macro-fail.rs:8:14\n  |\n8 | macro_rules! use_some_macro {\n  |              ^^^^^^^^^^^^^^\n  |\n  = note: `#[warn(unused_macros)]` on by default\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr/hook_macro-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[::yew::functional::hook]\npub fn use_some_macro_inner(val: &str) -> ::std::string::String {\n    let state = ::yew::functional::use_state(|| ::std::borrow::ToOwned::to_owned(val));\n    ::std::string::ToString::to_string(&*state)\n}\n\nmacro_rules! use_some_macro {\n    () => {\n        use_some_macro_inner(\"default str\")\n    };\n    ($t: tt) => {\n        use_some_macro_inner($t)\n    };\n}\n\n#[::yew::functional::component]\nfn Comp() -> ::yew::Html {\n    let a = use_some_macro!();\n    let b = use_some_macro!(\"b\");\n\n    ::yew::html! {\n        <div>{a}{b}</div>\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_attr_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn tests() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/hook_attr/*-pass.rs\");\n    t.compile_fail(\"tests/hook_attr/*-fail.rs\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_macro/use_prepared_state-fail.rs",
    "content": "use yew::prelude::*;\nuse yew_macro::{use_prepared_state_with_closure, use_prepared_state_without_closure};\n\n#[component]\nfn Comp() -> HtmlResult {\n    use_prepared_state_with_closure!(123)?;\n\n    use_prepared_state_with_closure!(123, |_| { todo!() })?;\n\n    use_prepared_state_with_closure!(|_| -> u32 { todo!() })?;\n\n    use_prepared_state_with_closure!(|_| -> u32 { todo!() }, 123)?;\n\n    use_prepared_state_with_closure!(async |_| -> u32 { todo!() })?;\n\n    use_prepared_state_with_closure!(|_| { todo!() }, 123)?;\n\n    Ok(Html::default())\n}\n\n#[component]\nfn Comp2() -> HtmlResult {\n    use_prepared_state_without_closure!(123)?;\n\n    use_prepared_state_without_closure!(123, |_| { todo!() })?;\n\n    use_prepared_state_without_closure!(|_| { todo!() }, 123)?;\n\n    use_prepared_state_without_closure!(|_| -> u32 { todo!() })?;\n\n    use_prepared_state_without_closure!(|_| -> u32 { todo!() }, 123)?;\n\n    use_prepared_state_without_closure!(async |_| -> u32 { todo!() })?;\n\n    Ok(Html::default())\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_macro/use_prepared_state-fail.stderr",
    "content": "error: this hook takes 2 arguments but 1 argument was supplied\n --> tests/hook_macro/use_prepared_state-fail.rs:6:5\n  |\n6 |     use_prepared_state_with_closure!(123)?;\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `use_prepared_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.\n --> tests/hook_macro/use_prepared_state-fail.rs:8:43\n  |\n8 |     use_prepared_state_with_closure!(123, |_| { todo!() })?;\n  |                                           ^^^^^^^^^^^^^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_prepared_state-fail.rs:10:5\n   |\n10 |     use_prepared_state_with_closure!(|_| -> u32 { todo!() })?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_prepared_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n  --> tests/hook_macro/use_prepared_state-fail.rs:12:62\n   |\n12 |     use_prepared_state_with_closure!(|_| -> u32 { todo!() }, 123)?;\n   |                                                              ^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_prepared_state-fail.rs:14:5\n   |\n14 |     use_prepared_state_with_closure!(async |_| -> u32 { todo!() })?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_prepared_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n  --> tests/hook_macro/use_prepared_state-fail.rs:16:55\n   |\n16 |     use_prepared_state_with_closure!(|_| { todo!() }, 123)?;\n   |                                                       ^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_prepared_state-fail.rs:23:5\n   |\n23 |     use_prepared_state_without_closure!(123)?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_prepared_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.\n  --> tests/hook_macro/use_prepared_state-fail.rs:25:46\n   |\n25 |     use_prepared_state_without_closure!(123, |_| { todo!() })?;\n   |                                              ^^^^^^^^^^^^^^^\n\nerror: expected closure\n  --> tests/hook_macro/use_prepared_state-fail.rs:27:58\n   |\n27 |     use_prepared_state_without_closure!(|_| { todo!() }, 123)?;\n   |                                                          ^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_prepared_state-fail.rs:29:5\n   |\n29 |     use_prepared_state_without_closure!(|_| -> u32 { todo!() })?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_prepared_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n  --> tests/hook_macro/use_prepared_state-fail.rs:31:65\n   |\n31 |     use_prepared_state_without_closure!(|_| -> u32 { todo!() }, 123)?;\n   |                                                                 ^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_prepared_state-fail.rs:33:5\n   |\n33 |     use_prepared_state_without_closure!(async |_| -> u32 { todo!() })?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_prepared_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_macro/use_transitive_state-fail.rs",
    "content": "use yew::prelude::*;\nuse yew_macro::{use_transitive_state_with_closure, use_transitive_state_without_closure};\n\n#[component]\nfn Comp() -> HtmlResult {\n    use_transitive_state_with_closure!(123)?;\n\n    use_transitive_state_with_closure!(|_| { todo!() }, 123)?;\n\n    use_transitive_state_with_closure!(123, |_| { todo!() })?;\n\n    use_transitive_state_with_closure!(|_| -> u32 { todo!() })?;\n\n    use_transitive_state_with_closure!(|_| -> u32 { todo!() }, 123)?;\n\n    Ok(Html::default())\n}\n\n#[component]\nfn Comp2() -> HtmlResult {\n    use_transitive_state_without_closure!(123)?;\n\n    use_transitive_state_without_closure!(|_| { todo!() }, 123)?;\n\n    use_transitive_state_without_closure!(123, |_| { todo!() })?;\n\n    use_transitive_state_without_closure!(|_| -> u32 { todo!() })?;\n\n    use_transitive_state_without_closure!(|_| -> u32 { todo!() }, 123)?;\n\n    Ok(Html::default())\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_macro/use_transitive_state-fail.stderr",
    "content": "error: this hook takes 2 arguments but 1 argument was supplied\n --> tests/hook_macro/use_transitive_state-fail.rs:6:5\n  |\n6 |     use_transitive_state_with_closure!(123)?;\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `use_transitive_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n --> tests/hook_macro/use_transitive_state-fail.rs:8:57\n  |\n8 |     use_transitive_state_with_closure!(|_| { todo!() }, 123)?;\n  |                                                         ^^^\n\nerror: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.\n  --> tests/hook_macro/use_transitive_state-fail.rs:10:45\n   |\n10 |     use_transitive_state_with_closure!(123, |_| { todo!() })?;\n   |                                             ^^^^^^^^^^^^^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_transitive_state-fail.rs:12:5\n   |\n12 |     use_transitive_state_with_closure!(|_| -> u32 { todo!() })?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_transitive_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n  --> tests/hook_macro/use_transitive_state-fail.rs:14:64\n   |\n14 |     use_transitive_state_with_closure!(|_| -> u32 { todo!() }, 123)?;\n   |                                                                ^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_transitive_state-fail.rs:21:5\n   |\n21 |     use_transitive_state_without_closure!(123)?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_transitive_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n  --> tests/hook_macro/use_transitive_state-fail.rs:23:60\n   |\n23 |     use_transitive_state_without_closure!(|_| { todo!() }, 123)?;\n   |                                                            ^^^\n\nerror: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.\n  --> tests/hook_macro/use_transitive_state-fail.rs:25:48\n   |\n25 |     use_transitive_state_without_closure!(123, |_| { todo!() })?;\n   |                                                ^^^^^^^^^^^^^^^\n\nerror: this hook takes 2 arguments but 1 argument was supplied\n  --> tests/hook_macro/use_transitive_state-fail.rs:27:5\n   |\n27 |     use_transitive_state_without_closure!(|_| -> u32 { todo!() })?;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `use_transitive_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected closure\n  --> tests/hook_macro/use_transitive_state-fail.rs:29:67\n   |\n29 |     use_transitive_state_without_closure!(|_| -> u32 { todo!() }, 123)?;\n   |                                                                   ^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/hook_macro_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn tests() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/hook_macro/*-pass.rs\");\n    t.compile_fail(\"tests/hook_macro/*-fail.rs\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_lints/fail.rs",
    "content": "use yew::prelude::*;\n\nfn main() {\n    let bad_a = html! {\n        <a>{ \"I don't have a href attribute\" }</a>\n    };\n    let bad_a_2 = html! {\n        <a href=\"#\">{ \"I have a malformed href attribute\" }</a>\n    };\n    let bad_a_3 = html! {\n        <a href=\"javascript:void(0)\">{ \"I have a malformed href attribute\" }</a>\n    };\n    let bad_img = html! {\n        <img src=\"img.jpeg\"/>\n    };\n    let malformed_tagname = html! {\n        <tExTAreA />\n    };\n    compile_error!(\"This macro call exists to deliberately fail the compilation of the test so we can verify output of lints\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_lints/fail.stderr",
    "content": "warning: The tag 'tExTAreA' is not matching its normalized form 'textarea' and is not a recognized SVG or MathML element. If you want to keep this name, you can use the dynamic tag `@{\"tExTAreA\"}` to silence this warning.\n  --> tests/html_lints/fail.rs:17:10\n   |\n17 |         <tExTAreA />\n   |          ^^^^^^^^\n\nerror: This macro call exists to deliberately fail the compilation of the test so we can verify output of lints\n  --> tests/html_lints/fail.rs:19:5\n   |\n19 |     compile_error!(\"This macro call exists to deliberately fail the compilation of the test so we can verify output of lints\");\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/html_lints_test.rs",
    "content": "#[allow(dead_code)]\n#[cfg(yew_lints)]\n#[rustversion::attr(nightly, test)]\nfn test_html_lints() {\n    let t = trybuild::TestCases::new();\n    t.compile_fail(\"tests/html_lints/fail.rs\");\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/as-return-value-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\npub struct MyComponent;\nimpl ::yew::Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\n// can test \"unused braces\" warning inside the macro\n// https://github.com/yewstack/yew/issues/2157\nfn make_my_component()-> ::yew::virtual_dom::VChild<MyComponent>{\n    ::yew::html_nested!{<MyComponent/>}\n}\n\n// can test \"unused braces\" warning inside the macro\n// https://github.com/yewstack/yew/issues/2157\nfn make_my_component_html()-> ::yew::Html{\n    ::yew::html!{<MyComponent/>}\n}\n\nfn main(){}"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/block-fail.rs",
    "content": "use yew::prelude::*;\n\nfn compile_fail() {\n    html! {\n        <>\n            { () }\n        </>\n    };\n\n    let not_tree = || ();\n    html! {\n        <div>{ not_tree() }</div>\n    };\n    html! {\n        <>{ for (0..3).map(|_| not_tree()) }</>\n    };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/block-fail.stderr",
    "content": "error[E0277]: the trait bound `(): Into<NodeSeq<(), VNode>>` is not satisfied\n --> tests/html_macro/block-fail.rs:6:15\n  |\n6 |             { () }\n  |               ^^\n  |               |\n  |               the trait `std::fmt::Display` is not implemented for `()`\n  |               required by a bound introduced by this call\n  |\n  = note: required for `()` to implement `ToString`\n  = note: required for `VNode` to implement `From<()>`\n  = note: required for `()` to implement `Into<VNode>`\n  = note: 2 redundant requirements hidden\n  = note: required for `()` to implement `Into<NodeSeq<(), VNode>>`\n\nerror[E0277]: the trait bound `(): Into<VNode>` is not satisfied\n  --> tests/html_macro/block-fail.rs:15:17\n   |\n15 |         <>{ for (0..3).map(|_| not_tree()) }</>\n   |                 ^^^^^^ the trait `std::fmt::Display` is not implemented for `()`\n   |\n   = note: required for `()` to implement `ToString`\n   = note: required for `VNode` to implement `From<()>`\n   = note: required for `()` to implement `Into<VNode>`\nnote: required by a bound in `into_node_iter`\n  --> $WORKSPACE/packages/yew/src/utils/mod.rs\n   |\n   | pub fn into_node_iter<IT, T, R>(it: IT) -> impl Iterator<Item = R>\n   |        -------------- required by a bound in this function\n...\n   |     T: Into<R>,\n   |        ^^^^^^^ required by this bound in `into_node_iter`\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/block-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn main() {\n    _ = ::yew::html! { <>{ \"Hi\" }</> };\n    _ = ::yew::html! { <>{ ::std::format!(\"Hello\") }</> };\n    _ = ::yew::html! { <>{ ::std::string::ToString::to_string(\"Hello\") }</> };\n\n    let msg = \"Hello\";\n    _ = ::yew::html! { <div>{ msg }</div> };\n\n    let subview = ::yew::html! { \"subview!\" };\n    _ = ::yew::html! { <div>{ subview }</div> };\n\n    let subview = || ::yew::html! { \"subview!\" };\n    _ = ::yew::html! { <div>{ subview() }</div> };\n\n    _ = ::yew::html! {\n        <ul>\n            { for ::std::iter::Iterator::map(0..3, |num| { ::yew::html! { <span>{ num }</span> }}) }\n        </ul>\n    };\n\n    let item = |num| ::yew::html! { <li>{ ::std::format!(\"item {}!\", num) }</li> };\n    _ = ::yew::html! {\n        <ul>\n            { for ::std::iter::Iterator::map(0..3, item) }\n        </ul>\n    };\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/component-any-children-pass.rs",
    "content": "// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct ContainerProperties {\n    pub int: ::std::primitive::i32,\n    // You can use Html as Children.\n    #[prop_or_default]\n    pub children: ::yew::Html,\n    #[prop_or_default]\n    pub header: ::yew::Html,\n}\n\npub struct Container;\nimpl ::yew::Component for Container {\n    type Message = ();\n    type Properties = ContainerProperties;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\n#[derive(::std::clone::Clone, ::std::cmp::PartialEq)]\npub enum ChildrenVariants {\n    Child(::yew::virtual_dom::VChild<Child>),\n    AltChild(::yew::virtual_dom::VChild<AltChild>),\n}\n\nimpl ::std::convert::From<::yew::virtual_dom::VChild<Child>> for ChildrenVariants {\n    fn from(comp: ::yew::virtual_dom::VChild<Child>) -> Self {\n        ChildrenVariants::Child(comp)\n    }\n}\n\nimpl ::std::convert::From<::yew::virtual_dom::VChild<AltChild>> for ChildrenVariants {\n    fn from(comp: ::yew::virtual_dom::VChild<AltChild>) -> Self {\n        ChildrenVariants::AltChild(comp)\n    }\n}\n\nimpl ::std::convert::Into<::yew::virtual_dom::VNode> for ChildrenVariants {\n    fn into(self) -> ::yew::virtual_dom::VNode {\n        match self {\n            Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::<\n                ::yew::virtual_dom::VComp,\n            >::into(comp))),\n            Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::<\n                ::yew::virtual_dom::VComp,\n            >::into(comp))),\n        }\n    }\n}\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct ChildProperties {\n    #[prop_or_default]\n    pub string: ::std::string::String,\n    #[prop_or_default]\n    pub r#fn: ::std::primitive::i32,\n    #[prop_or_default]\n    pub r#ref: ::yew::NodeRef,\n    pub int: ::std::primitive::i32,\n    #[prop_or_default]\n    pub opt_str: ::std::option::Option<::std::string::String>,\n    #[prop_or_default]\n    pub vec: ::std::vec::Vec<::std::primitive::i32>,\n    #[prop_or_default]\n    pub optional_callback: ::std::option::Option<::yew::Callback<()>>,\n}\n\npub struct Child;\nimpl ::yew::Component for Child {\n    type Message = ();\n    type Properties = ChildProperties;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\npub struct AltChild;\nimpl ::yew::Component for AltChild {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\nmod scoped {\n    pub use super::{Child, Container};\n}\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct RenderPropProps {\n    // You can use Callback<()> as Children.\n    #[prop_or_default]\n    pub children: ::yew::Callback<()>,\n}\n\n#[::yew::component]\npub fn RenderPropComp(_props: &RenderPropProps) -> ::yew::Html {\n    ::yew::html! {}\n}\n\nfn compile_pass() {\n    _ = ::yew::html! { <Child int=1 /> };\n    _ = ::yew::html! { <Child int=1 r#fn=1 /> };\n\n    _ = ::yew::html! {\n        <>\n            <Child int=1 />\n            <scoped::Child int=1 />\n        </>\n    };\n\n    let props = <<Child as ::yew::Component>::Properties as ::std::default::Default>::default();\n    let node_ref = <::yew::NodeRef as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Child ..::std::clone::Clone::clone(&props) />\n            <Child int={1} ..props />\n            <Child r#ref={::std::clone::Clone::clone(&node_ref)} int={2} ..::yew::props!(Child::Properties { int: 5 }) />\n            <Child int=3 r#ref={::std::clone::Clone::clone(&node_ref)} ..::yew::props!(Child::Properties { int: 5 }) />\n            <Child r#ref={::std::clone::Clone::clone(&node_ref)} ..::yew::props!(Child::Properties { int: 5 }) />\n            <Child r#ref={&node_ref} ..<<Child as ::yew::Component>::Properties as ::std::default::Default>::default() />\n            <Child r#ref={node_ref} ..<<Child as ::yew::Component>::Properties as ::std::default::Default>::default() />\n        </>\n    };\n\n    _ = ::yew::html! {\n        <>\n            <Child int=1 string=\"child\" />\n            <Child int=1 />\n            <Child int={1+1} />\n            <Child int=1 vec={::std::vec![1]} />\n            <Child string={<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from(\"child\")} int=1 />\n\n            <Child opt_str=\"child\" int=1 />\n            <Child opt_str={<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from(\"child\")} int=1 />\n            <Child opt_str={::std::option::Option::Some(\"child\")} int=1 />\n            <Child opt_str={::std::option::Option::Some(<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from(\"child\"))} int=1 />\n        </>\n    };\n\n    let name_expr = \"child\";\n    _ = ::yew::html! {\n        <Child int=1 string={name_expr} />\n    };\n\n    let string = \"child\";\n    let int = 1;\n    _ = ::yew::html! {\n        <Child {int} {string} />\n    };\n\n    _ = ::yew::html! {\n        <>\n            <Child int=1 />\n            <Child int=1 optional_callback={::std::option::Option::Some(<::yew::Callback<()> as ::std::convert::From<_>>::from(|_| ()))} />\n            <Child int=1 optional_callback={<::yew::Callback<()> as ::std::convert::From<_>>::from(|_| ())} />\n            <Child int=1 optional_callback={::std::option::Option::None::<::yew::Callback<_>>} />\n        </>\n    };\n\n    let node_ref = <::yew::NodeRef as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Child int=1 r#ref={node_ref} />\n        </>\n    };\n\n    let int = 1;\n    let node_ref = <::yew::NodeRef as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Child {int} r#ref={node_ref} />\n        </>\n    };\n\n    let props = <<Container as ::yew::Component>::Properties as ::std::default::Default>::default();\n    let child_props =\n        <<Child as ::yew::Component>::Properties as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Container int=1 />\n            <Container int=1></Container>\n\n            <Container ..::std::clone::Clone::clone(&props)>\n                <div>{ \"hello world\" }</div>\n            </Container>\n\n            <Container int=1 ..::std::clone::Clone::clone(&props)>\n                <div>{ \"hello world\" }</div>\n            </Container>\n\n            <Container int=1 ..::std::clone::Clone::clone(&props)>\n                <Child int=2 opt_str=\"hello\" ..::std::clone::Clone::clone(&child_props) />\n            </Container>\n\n            <Container int=1 ..::std::clone::Clone::clone(&props)>\n                <Child int=2 vec={::std::vec![0]} ..::std::clone::Clone::clone(&child_props) />\n            </Container>\n\n\n            <Container int=1 ..props>\n                <Child int=2 string=\"hello\" ..child_props />\n            </Container>\n\n            <Container int=1>\n                <Child int=2 />\n            </Container>\n\n            <scoped::Container int=1>\n                <scoped::Container int=2/>\n            </scoped::Container>\n\n            <Container int=1 children={::yew::html::ChildrenRenderer::new(\n                ::std::vec![::yew::html!{ \"::std::string::String\" }]\n            )} />\n            <Container int=1 header={::yew::html!{\n                <Child int=2 />\n            }} />\n        </>\n    };\n\n    let variants = || -> ::std::vec::Vec<ChildrenVariants> {\n        ::std::vec![\n            ChildrenVariants::Child(::yew::virtual_dom::VChild::new(\n                <ChildProperties as ::std::default::Default>::default(),\n                ::std::option::Option::None,\n            )),\n            ChildrenVariants::AltChild(::yew::virtual_dom::VChild::new(\n                (),\n                ::std::option::Option::None\n            )),\n        ]\n    };\n\n    _ = ::yew::html! {\n        <>\n            {\n                ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(\n                    ::std::iter::Iterator::filter(\n                        ::std::iter::IntoIterator::into_iter(variants()),\n                        |c| match c {\n                            ChildrenVariants::Child(_) => true,\n                            _ => false,\n                        }\n                    )\n                )\n            }\n            <div>\n                {\n                    ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(\n                        ::std::iter::Iterator::filter(\n                            ::std::iter::IntoIterator::into_iter(variants()),\n                            |c| match c {\n                                ChildrenVariants::AltChild(_) => true,\n                                _ => false,\n                            }\n                        )\n                    )\n                }\n            </div>\n        </>\n    };\n\n    _ = ::yew::html_nested! { 1 };\n\n    _ = ::yew::html! {\n        <RenderPropComp>\n            {|_arg| {}}\n        </RenderPropComp>\n    };\n}\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/component-fail.rs",
    "content": "use yew::html::ChildrenRenderer;\nuse yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\npub struct ChildProperties {\n    #[prop_or_default]\n    pub string: String,\n    pub int: i32,\n}\n\npub struct Child;\nimpl Component for Child {\n    type Message = ();\n    type Properties = ChildProperties;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        unimplemented!()\n    }\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        unimplemented!()\n    }\n}\n\n#[derive(Clone, Properties, PartialEq)]\npub struct ChildContainerProperties {\n    pub children: ChildrenWithProps<Child>,\n}\n\npub struct ChildContainer;\nimpl Component for ChildContainer {\n    type Message = ();\n    type Properties = ChildContainerProperties;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        unimplemented!()\n    }\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        unimplemented!()\n    }\n}\n\nfn compile_fail() {\n    html! { <Child> };\n    html! { <Child:: /> };\n    html! { <Child with /> };\n    html! { <Child .. /> };\n    html! { <Child ..{ 5 + } /> };\n    html! { <Child props /> };\n    html! { <Child with props > };\n    html! { <Child ..props > };\n    let (p1, p2);\n    html! { <Child with p1 with p2 /> };\n    html! { <Child ..p1 ..p2 /> };\n    html! { <Child with props ref={()} ref={()} /> };\n    html! { <Child ..props ref={()} ref={()} /> };\n    html! { <Child with props ref={()} ref={()} value=1 /> };\n    html! { <Child ..props ref={()} ref={()} value=1 /> };\n    html! { <Child with props ref={()} value=1 ref={()} /> };\n    html! { <Child ..props ref={()} value=1 ref={()} /> };\n    html! { <Child with props value=1 ref={()}  ref={()} /> };\n    html! { <Child ..props value=1 ref={()}  ref={()} /> };\n    html! { <Child value=1 with props  ref={()}  ref={()} /> };\n    html! { <Child value=1 ..props  ref={()}  ref={()} /> };\n    html! { <Child value=1 ref={()} with props ref={()} /> };\n    html! { <Child value=1 ref={()} ..props ref={()} /> };\n    html! { <Child ref={()} ref={()} value=1  with props  /> };\n    html! { <Child ref={()} ref={()} value=1 ..props  /> };\n    html! { <Child with props r#ref={()} r#ref={()} /> };\n    html! { <Child ..props r#ref={()} r#ref={()} /> };\n    html! { <Child with props r#ref={()} r#ref={()} value=1 /> };\n    html! { <Child ..props r#ref={()} r#ref={()} value=1 /> };\n    html! { <Child with props r#ref={()} value=1 r#ref={()} /> };\n    html! { <Child ..props r#ref={()} value=1 r#ref={()} /> };\n    html! { <Child with props value=1 r#ref={()}  r#ref={()} /> };\n    html! { <Child ..props value=1 r#ref={()}  r#ref={()} /> };\n    html! { <Child value=1 with props  r#ref={()}  r#ref={()} /> };\n    html! { <Child value=1 ..props  r#ref={()}  r#ref={()} /> };\n    html! { <Child value=1 r#ref={()} with props r#ref={()} /> };\n    html! { <Child value=1 r#ref={()} ..props r#ref={()} /> };\n    html! { <Child r#ref={()} r#ref={()} value=1  with props  /> };\n    html! { <Child r#ref={()} r#ref={()} value=1 ..props  /> };\n    html! { <Child ..blah /> };\n    html! { <Child value=1 ..props /> };\n    html! { <Child .. props value=1 /> };\n    html! { <Child type=0 /> };\n    html! { <Child ref=() /> };\n    html! { <Child invalid-prop-name=0 /> };\n    html! { <Child unknown=\"unknown\" /> };\n    html! { <Child string= /> };\n    html! { <Child int=1 int=2 int=3 /> };\n    html! { <Child int=1 string={} /> };\n    html! { <Child int=1 string=3 /> };\n    html! { <Child int=1 string={3} /> };\n    html! { <Child int=1 ref={()} /> };\n    html! { <Child int=1 ref={()} ref={()} /> };\n    html! { <Child int=1 r#ref={()} /> };\n    html! { <Child int=1 r#ref={()} r#ref={()} /> };\n    html! { <Child int=0u32 /> };\n    html! { <Child string=\"abc\" /> };\n    html! { </Child> };\n    html! { <Child><Child></Child> };\n    html! { <Child></Child><Child></Child> };\n    html! { <Child>{ \"Not allowed\" }</Child> };\n\n    let num = 1;\n    html! { <Child int=num ..props /> };\n\n    // trying to overwrite `children` on props which don't take any.\n    html! {\n        <Child ..ChildProperties { string: \"hello\".to_owned(), int: 5 }>\n            { \"please error\" }\n        </Child>\n    };\n\n    html! { <ChildContainer /> };\n    html! { <ChildContainer></ChildContainer> };\n    html! { <ChildContainer>{ \"Not allowed\" }</ChildContainer> };\n    html! { <ChildContainer><></></ChildContainer> };\n    html! { <ChildContainer><other /></ChildContainer> };\n\n    // using `children` as a prop while simultaneously passing children using the syntactic sugar\n    let children = ChildrenRenderer::new(vec![html_nested! { <Child int=0 /> }]);\n    html! {\n        <ChildContainer {children}>\n            <Child int=1 />\n        </ChildContainer>\n    };\n\n    html_nested! {\n        <span>{ 1 }</span>\n        <span>{ 2 }</span>\n    };\n\n    html! { <Child {std::f64::consts::PI} /> };\n    html! { <Child {7 + 6} /> };\n    html! { <Child {children.len()} /> };\n}\n\n#[derive(Clone, Properties, PartialEq)]\npub struct HtmlInPropsProperties {\n    pub header: ::yew::Html,\n}\n#[component]\nfn HtmlInProps(props: &HtmlInPropsProperties) -> Html { let _ = (); unimplemented!() }\n\nfn not_expressions() {\n    html! { <HtmlInProps header={macro_rules! declare { }} /> };\n    html! { <HtmlInProps header={format!(\"ending with semi\");} /> };\n}\n\nfn mismatch_closing_tags() {\n    pub struct A;\n    impl Component for A {\n        type Message = ();\n        type Properties = ();\n\n        fn create(_ctx: &Context<Self>) -> Self {\n            unimplemented!()\n        }\n        fn view(&self, _ctx: &Context<Self>) -> Html {\n            unimplemented!()\n        }\n    }\n\n    pub struct B;\n    impl Component for B {\n        type Message = ();\n        type Properties = ();\n\n        fn create(_ctx: &Context<Self>) -> Self {\n            unimplemented!()\n        }\n        fn view(&self, _ctx: &Context<Self>) -> Html {\n            unimplemented!()\n        }\n    }\n    let _ = html! { <A></B> };\n    let _ = html! { <A></> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/component-fail.stderr",
    "content": "error: this opening tag has no corresponding closing tag\n  --> tests/html_macro/component-fail.rs:43:13\n   |\n43 |     html! { <Child> };\n   |             ^^^^^^^\n\nerror: unexpected end of input, expected identifier\n  --> tests/html_macro/component-fail.rs:44:13\n   |\n44 |     html! { <Child:: /> };\n   |             ^^^^^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:45:20\n   |\n45 |     html! { <Child with /> };\n   |                    ^^^^\n\nerror: expected base props expression after `..`\n  --> tests/html_macro/component-fail.rs:46:20\n   |\n46 |     html! { <Child .. /> };\n   |                    ^^\n\nerror: unexpected end of input, expected an expression\n  --> tests/html_macro/component-fail.rs:46:13\n   |\n46 |     html! { <Child .. /> };\n   |             ^^^^^^^^^^^^\n\nerror: expected base props expression after `..`\n  --> tests/html_macro/component-fail.rs:47:20\n   |\n47 |     html! { <Child ..{ 5 + } /> };\n   |                    ^^\n\nerror: unexpected end of input, expected an expression\n  --> tests/html_macro/component-fail.rs:47:28\n   |\n47 |     html! { <Child ..{ 5 + } /> };\n   |                            ^\n\nerror: `props` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:48:20\n   |\n48 |     html! { <Child props /> };\n   |                    ^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:49:20\n   |\n49 |     html! { <Child with props > };\n   |                    ^^^^\n\nerror: this opening tag has no corresponding closing tag\n  --> tests/html_macro/component-fail.rs:50:13\n   |\n50 |     html! { <Child ..props > };\n   |             ^^^^^^^^^^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:52:20\n   |\n52 |     html! { <Child with p1 with p2 /> };\n   |                    ^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:54:20\n   |\n54 |     html! { <Child with props ref={()} ref={()} /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:55:20\n   |\n55 |     html! { <Child ..props ref={()} ref={()} /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:56:20\n   |\n56 |     html! { <Child with props ref={()} ref={()} value=1 /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:57:20\n   |\n57 |     html! { <Child ..props ref={()} ref={()} value=1 /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:58:20\n   |\n58 |     html! { <Child with props ref={()} value=1 ref={()} /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:59:20\n   |\n59 |     html! { <Child ..props ref={()} value=1 ref={()} /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:60:20\n   |\n60 |     html! { <Child with props value=1 ref={()}  ref={()} /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:61:20\n   |\n61 |     html! { <Child ..props value=1 ref={()}  ref={()} /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:62:28\n   |\n62 |     html! { <Child value=1 with props  ref={()}  ref={()} /> };\n   |                            ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:63:28\n   |\n63 |     html! { <Child value=1 ..props  ref={()}  ref={()} /> };\n   |                            ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:64:37\n   |\n64 |     html! { <Child value=1 ref={()} with props ref={()} /> };\n   |                                     ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:65:37\n   |\n65 |     html! { <Child value=1 ref={()} ..props ref={()} /> };\n   |                                     ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:66:47\n   |\n66 |     html! { <Child ref={()} ref={()} value=1  with props  /> };\n   |                                               ^^^^\n\nerror: `ref` can only be specified once\n  --> tests/html_macro/component-fail.rs:67:29\n   |\n67 |     html! { <Child ref={()} ref={()} value=1 ..props  /> };\n   |                             ^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:68:20\n   |\n68 |     html! { <Child with props r#ref={()} r#ref={()} /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:69:20\n   |\n69 |     html! { <Child ..props r#ref={()} r#ref={()} /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:70:20\n   |\n70 |     html! { <Child with props r#ref={()} r#ref={()} value=1 /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:71:20\n   |\n71 |     html! { <Child ..props r#ref={()} r#ref={()} value=1 /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:72:20\n   |\n72 |     html! { <Child with props r#ref={()} value=1 r#ref={()} /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:73:20\n   |\n73 |     html! { <Child ..props r#ref={()} value=1 r#ref={()} /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:74:20\n   |\n74 |     html! { <Child with props value=1 r#ref={()}  r#ref={()} /> };\n   |                    ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:75:20\n   |\n75 |     html! { <Child ..props value=1 r#ref={()}  r#ref={()} /> };\n   |                    ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:76:28\n   |\n76 |     html! { <Child value=1 with props  r#ref={()}  r#ref={()} /> };\n   |                            ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:77:28\n   |\n77 |     html! { <Child value=1 ..props  r#ref={()}  r#ref={()} /> };\n   |                            ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:78:39\n   |\n78 |     html! { <Child value=1 r#ref={()} with props r#ref={()} /> };\n   |                                       ^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:79:39\n   |\n79 |     html! { <Child value=1 r#ref={()} ..props r#ref={()} /> };\n   |                                       ^^^^^^^\n\nerror: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> tests/html_macro/component-fail.rs:80:51\n   |\n80 |     html! { <Child r#ref={()} r#ref={()} value=1  with props  /> };\n   |                                                   ^^^^\n\nerror: `r#ref` can only be specified once but is given here again\n  --> tests/html_macro/component-fail.rs:81:31\n   |\n81 |     html! { <Child r#ref={()} r#ref={()} value=1 ..props  /> };\n   |                               ^^^^^\n\nerror: base props expression must appear last in list of props\n  --> tests/html_macro/component-fail.rs:84:20\n   |\n84 |     html! { <Child .. props value=1 /> };\n   |                    ^^^^^^^^\n\nerror: expected identifier, found keyword `type`\n  --> tests/html_macro/component-fail.rs:85:20\n   |\n85 |     html! { <Child type=0 /> };\n   |                    ^^^^ expected identifier, found keyword\n   |\nhelp: escape `type` to use it as an identifier\n   |\n85 |     html! { <Child r#type=0 /> };\n   |                    ++\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple {\n           attrs: [],\n           paren_token: Paren,\n           elems: [],\n       }\n  --> tests/html_macro/component-fail.rs:86:24\n   |\n86 |     html! { <Child ref=() /> };\n   |                        ^^\n\nerror: expected a valid Rust identifier\n  --> tests/html_macro/component-fail.rs:87:20\n   |\n87 |     html! { <Child invalid-prop-name=0 /> };\n   |                    ^^^^^^^^^^^^^^^^^\n\nerror: expected an expression following this equals sign\n  --> tests/html_macro/component-fail.rs:89:26\n   |\n89 |     html! { <Child string= /> };\n   |                          ^\n\nerror: `int` can only be specified once but is given here again\n  --> tests/html_macro/component-fail.rs:90:26\n   |\n90 |     html! { <Child int=1 int=2 int=3 /> };\n   |                          ^^^\n\nerror: `int` can only be specified once but is given here again\n  --> tests/html_macro/component-fail.rs:90:32\n   |\n90 |     html! { <Child int=1 int=2 int=3 /> };\n   |                                ^^^\n\nerror: cannot use `ref` with components. If you want to specify a property, use `r#ref` here instead.\n  --> tests/html_macro/component-fail.rs:94:26\n   |\n94 |     html! { <Child int=1 ref={()} /> };\n   |                          ^^^\n\nerror: `ref` can only be specified once\n  --> tests/html_macro/component-fail.rs:95:35\n   |\n95 |     html! { <Child int=1 ref={()} ref={()} /> };\n   |                                   ^^^\n\nerror: `r#ref` can only be specified once but is given here again\n  --> tests/html_macro/component-fail.rs:97:37\n   |\n97 |     html! { <Child int=1 r#ref={()} r#ref={()} /> };\n   |                                     ^^^^^\n\nerror: this closing tag has no corresponding opening tag\n   --> tests/html_macro/component-fail.rs:100:13\n    |\n100 |     html! { </Child> };\n    |             ^^^^^^^^\n\nerror: this opening tag has no corresponding closing tag\n   --> tests/html_macro/component-fail.rs:101:13\n    |\n101 |     html! { <Child><Child></Child> };\n    |             ^^^^^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n   --> tests/html_macro/component-fail.rs:102:28\n    |\n102 |     html! { <Child></Child><Child></Child> };\n    |                            ^^^^^^^^^^^^^^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Path {\n           attrs: [],\n           qself: None,\n           path: Path {\n               leading_colon: None,\n               segments: [\n                   PathSegment {\n                       ident: Ident {\n                           ident: \"num\",\n                           span: #0 bytes(3894..3897),\n                       },\n                       arguments: PathArguments::None,\n                   },\n               ],\n           },\n       }\n   --> tests/html_macro/component-fail.rs:106:24\n    |\n106 |     html! { <Child int=num ..props /> };\n    |                        ^^^\n\nerror: cannot specify the `children` prop when the component already has children\n   --> tests/html_macro/component-fail.rs:124:26\n    |\n124 |         <ChildContainer {children}>\n    |                          ^^^^^^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n   --> tests/html_macro/component-fail.rs:131:9\n    |\n131 |         <span>{ 2 }</span>\n    |         ^^^^^^^^^^^^^^^^^^\n\nerror: only simple identifiers are allowed in the shorthand property syntax\n   --> tests/html_macro/component-fail.rs:134:21\n    |\n134 |     html! { <Child {std::f64::consts::PI} /> };\n    |                     ^^^^^^^^^^^^^^^^^^^^\n\nerror: missing label for property value. If trying to use the shorthand property syntax, only identifiers may be used\n   --> tests/html_macro/component-fail.rs:135:21\n    |\n135 |     html! { <Child {7 + 6} /> };\n    |                     ^^^^^\n\nerror: missing label for property value. If trying to use the shorthand property syntax, only identifiers may be used\n   --> tests/html_macro/component-fail.rs:136:21\n    |\n136 |     html! { <Child {children.len()} /> };\n    |                     ^^^^^^^^^^^^^^\n\nerror: only an expression may be assigned as a property\n   --> tests/html_macro/component-fail.rs:147:34\n    |\n147 |     html! { <HtmlInProps header={macro_rules! declare { }} /> };\n    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^\n\nerror: mismatched closing tags: expected `A`, found `B`\n   --> tests/html_macro/component-fail.rs:177:22\n    |\n177 |     let _ = html! { <A></B> };\n    |                      ^^^^^\n\nerror: expected a valid closing tag for component\n       note: found opening tag `<A>`\n       help: try `</A>`\n   --> tests/html_macro/component-fail.rs:178:24\n    |\n178 |     let _ = html! { <A></> };\n    |                        ^^^\n\nerror[E0425]: cannot find value `blah` in this scope\n  --> tests/html_macro/component-fail.rs:82:22\n   |\n82 |     html! { <Child ..blah /> };\n   |                      ^^^^ not found in this scope\n\nerror[E0425]: cannot find value `props` in this scope\n  --> tests/html_macro/component-fail.rs:83:30\n   |\n83 |     html! { <Child value=1 ..props /> };\n   |                              ^^^^^ not found in this scope\n\nerror[E0308]: mismatched types\n  --> tests/html_macro/component-fail.rs:53:22\n   |\n53 |     html! { <Child ..p1 ..p2 /> };\n   |              -----   ^^^^^^^ expected `ChildProperties`, found `Range<_>`\n   |              |\n   |              expected due to this\n   |\n   = note: expected struct `ChildProperties`\n              found struct `std::ops::Range<_>`\n\nerror[E0609]: no field `value` on type `ChildProperties`\n  --> tests/html_macro/component-fail.rs:83:20\n   |\n83 |     html! { <Child value=1 ..props /> };\n   |                    ^^^^^ unknown field\n   |\n   = note: available fields are: `string`, `int`\n\nerror[E0609]: no field `r#type` on type `ChildProperties`\n  --> tests/html_macro/component-fail.rs:85:20\n   |\n85 |     html! { <Child type=0 /> };\n   |                    ^^^^ unknown field\n   |\n   = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `r#type` found for struct `ChildPropertiesBuilder` in the current scope\n  --> tests/html_macro/component-fail.rs:85:20\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `r#type` not found for this struct\n...\n85 |     html! { <Child type=0 /> };\n   |                    ^^^^\n   |\nhelp: there is a method `type_id` with a similar name, but with different arguments\n  --> $RUST/core/src/any.rs\n\nerror[E0609]: no field `unknown` on type `ChildProperties`\n  --> tests/html_macro/component-fail.rs:88:20\n   |\n88 |     html! { <Child unknown=\"unknown\" /> };\n   |                    ^^^^^^^ unknown field\n   |\n   = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `unknown` found for struct `ChildPropertiesBuilder` in the current scope\n  --> tests/html_macro/component-fail.rs:88:20\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `unknown` not found for this struct\n...\n88 |     html! { <Child unknown=\"unknown\" /> };\n   |                    ^^^^^^^ method not found in `ChildPropertiesBuilder`\n\nerror[E0277]: the trait bound `(): IntoPropValue<String>` is not satisfied\n  --> tests/html_macro/component-fail.rs:91:33\n   |\n91 |     html! { <Child int=1 string={} /> };\n   |                          ------ ^^ the trait `IntoPropValue<String>` is not implemented for `()`\n   |                          |\n   |                          required by a bound introduced by this call\n   |\n   = help: the trait `IntoPropValue<String>` is not implemented for `()`\n           but trait `IntoPropValue<VNode>` is implemented for it\n   = help: for that trait implementation, expected `VNode`, found `String`\nnote: required by a bound in `ChildPropertiesBuilder::string`\n  --> tests/html_macro/component-fail.rs:4:17\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ^^^^^^^^^^ required by this bound in `ChildPropertiesBuilder::string`\n...\n7  |     pub string: String,\n   |         ------ required by a bound in this associated function\n   = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfied\n  --> tests/html_macro/component-fail.rs:92:33\n   |\n92 |     html! { <Child int=1 string=3 /> };\n   |                          ------ ^ the trait `IntoPropValue<String>` is not implemented for `{integer}`\n   |                          |\n   |                          required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `&f32` implements `IntoPropValue<Option<VNode>>`\n             `&f32` implements `IntoPropValue<VNode>`\n             `&f64` implements `IntoPropValue<Option<VNode>>`\n             `&f64` implements `IntoPropValue<VNode>`\n             `&i128` implements `IntoPropValue<Option<VNode>>`\n             `&i128` implements `IntoPropValue<VNode>`\n             `&i16` implements `IntoPropValue<Option<VNode>>`\n             `&i16` implements `IntoPropValue<VNode>`\n           and $N others\nnote: required by a bound in `ChildPropertiesBuilder::string`\n  --> tests/html_macro/component-fail.rs:4:17\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ^^^^^^^^^^ required by this bound in `ChildPropertiesBuilder::string`\n...\n7  |     pub string: String,\n   |         ------ required by a bound in this associated function\n   = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfied\n  --> tests/html_macro/component-fail.rs:93:34\n   |\n93 |     html! { <Child int=1 string={3} /> };\n   |                          ------  ^ the trait `IntoPropValue<String>` is not implemented for `{integer}`\n   |                          |\n   |                          required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `&f32` implements `IntoPropValue<Option<VNode>>`\n             `&f32` implements `IntoPropValue<VNode>`\n             `&f64` implements `IntoPropValue<Option<VNode>>`\n             `&f64` implements `IntoPropValue<VNode>`\n             `&i128` implements `IntoPropValue<Option<VNode>>`\n             `&i128` implements `IntoPropValue<VNode>`\n             `&i16` implements `IntoPropValue<Option<VNode>>`\n             `&i16` implements `IntoPropValue<VNode>`\n           and $N others\nnote: required by a bound in `ChildPropertiesBuilder::string`\n  --> tests/html_macro/component-fail.rs:4:17\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ^^^^^^^^^^ required by this bound in `ChildPropertiesBuilder::string`\n...\n7  |     pub string: String,\n   |         ------ required by a bound in this associated function\n   = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0609]: no field `r#ref` on type `ChildProperties`\n  --> tests/html_macro/component-fail.rs:96:26\n   |\n96 |     html! { <Child int=1 r#ref={()} /> };\n   |                          ^^^^^ unknown field\n   |\n   = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `r#ref` found for struct `ChildPropertiesBuilder` in the current scope\n  --> tests/html_macro/component-fail.rs:96:26\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `r#ref` not found for this struct\n...\n96 |     html! { <Child int=1 r#ref={()} /> };\n   |                          ^^^^^ method not found in `ChildPropertiesBuilder`\n\nerror[E0277]: the trait bound `u32: IntoPropValue<i32>` is not satisfied\n  --> tests/html_macro/component-fail.rs:98:24\n   |\n98 |     html! { <Child int=0u32 /> };\n   |                    --- ^^^^ the trait `IntoPropValue<i32>` is not implemented for `u32`\n   |                    |\n   |                    required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `&u32` implements `IntoPropValue<Option<VNode>>`\n             `&u32` implements `IntoPropValue<VNode>`\n             `u32` implements `IntoPropValue<Option<VNode>>`\n             `u32` implements `IntoPropValue<VNode>`\nnote: required by a bound in `ChildPropertiesBuilder::int`\n  --> tests/html_macro/component-fail.rs:4:17\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ^^^^^^^^^^ required by this bound in `ChildPropertiesBuilder::int`\n...\n8  |     pub int: i32,\n   |         --- required by a bound in this associated function\n   = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: not all required properties have been provided\n  --> tests/html_macro/component-fail.rs:99:14\n   |\n99 |     html! { <Child string=\"abc\" /> };\n   |              ^^^^^ missing required properties for this component\n   |\n   = help: the trait `HasProp<int, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildContainerPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckChildPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckHtmlInPropsPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasChildContainerPropertieschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasChildContainerPropertieschildren<B>` implements `HasProp<_ChildContainerProperties::children, HasChildContainerPropertieschildren<B>>`\n             `HasChildPropertiesint<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `CheckChildPropertiesAll<AssertAllProps>` to implement `HasAllProps<ChildProperties, (_,)>`\n  --> tests/html_macro/component-fail.rs:4:17\n   |\n4  | #[derive(Clone, Properties, PartialEq)]\n   |                 ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `AssertAllProps` to implement `AllPropsFor<ChildPropertiesBuilder, (_,)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0609]: no field `children` on type `ChildProperties`\n   --> tests/html_macro/component-fail.rs:103:14\n    |\n103 |     html! { <Child>{ \"Not allowed\" }</Child> };\n    |              ^^^^^ unknown field\n    |\n    = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0599]: no method named `children` found for struct `ChildPropertiesBuilder` in the current scope\n   --> tests/html_macro/component-fail.rs:103:14\n    |\n4   | #[derive(Clone, Properties, PartialEq)]\n    |                 ---------- method `children` not found for this struct\n...\n103 |     html! { <Child>{ \"Not allowed\" }</Child> };\n    |              ^^^^^ method not found in `ChildPropertiesBuilder`\n    |\n    = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0609]: no field `children` on type `ChildProperties`\n   --> tests/html_macro/component-fail.rs:110:10\n    |\n110 |         <Child ..ChildProperties { string: \"hello\".to_owned(), int: 5 }>\n    |          ^^^^^ unknown field\n    |\n    = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: not all required properties have been provided\n   --> tests/html_macro/component-fail.rs:115:14\n    |\n115 |     html! { <ChildContainer /> };\n    |              ^^^^^^^^^^^^^^ missing required properties for this component\n    |\n    = help: the trait `HasProp<_ChildContainerProperties::children, _>` is not implemented for `AssertAllProps`\n    = help: the following other types implement trait `HasProp<P, How>`:\n              `CheckChildContainerPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckChildPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckHtmlInPropsPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `HasChildContainerPropertieschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `HasChildContainerPropertieschildren<B>` implements `HasProp<_ChildContainerProperties::children, HasChildContainerPropertieschildren<B>>`\n              `HasChildPropertiesint<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n            and $N others\nnote: required for `CheckChildContainerPropertiesAll<AssertAllProps>` to implement `HasAllProps<ChildContainerProperties, (_,)>`\n   --> tests/html_macro/component-fail.rs:24:17\n    |\n24  | #[derive(Clone, Properties, PartialEq)]\n    |                 ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n    = note: required for `AssertAllProps` to implement `AllPropsFor<ChildContainerPropertiesBuilder, (_,)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n   --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n    |\n    |         pub fn build<How>(self) -> B::Output\n    |                ----- required by a bound in this associated function\n    |         where\n    |             Token: AllPropsFor<B, How>,\n    |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n    = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: not all required properties have been provided\n   --> tests/html_macro/component-fail.rs:116:14\n    |\n116 |     html! { <ChildContainer></ChildContainer> };\n    |              ^^^^^^^^^^^^^^ missing required properties for this component\n    |\n    = help: the trait `HasProp<_ChildContainerProperties::children, _>` is not implemented for `AssertAllProps`\n    = help: the following other types implement trait `HasProp<P, How>`:\n              `CheckChildContainerPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckChildPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `CheckHtmlInPropsPropertiesAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `HasChildContainerPropertieschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n              `HasChildContainerPropertieschildren<B>` implements `HasProp<_ChildContainerProperties::children, HasChildContainerPropertieschildren<B>>`\n              `HasChildPropertiesint<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n            and $N others\nnote: required for `CheckChildContainerPropertiesAll<AssertAllProps>` to implement `HasAllProps<ChildContainerProperties, (_,)>`\n   --> tests/html_macro/component-fail.rs:24:17\n    |\n24  | #[derive(Clone, Properties, PartialEq)]\n    |                 ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n    = note: required for `AssertAllProps` to implement `AllPropsFor<ChildContainerPropertiesBuilder, (_,)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n   --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n    |\n    |         pub fn build<How>(self) -> B::Output\n    |                ----- required by a bound in this associated function\n    |         where\n    |             Token: AllPropsFor<B, How>,\n    |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n    = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `yew::virtual_dom::VText: IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not satisfied\n   --> tests/html_macro/component-fail.rs:117:31\n    |\n117 |     html! { <ChildContainer>{ \"Not allowed\" }</ChildContainer> };\n    |              --------------   ^^^^^^^^^^^^^ the trait `IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not implemented for `yew::virtual_dom::VText`\n    |              |\n    |              required by a bound introduced by this call\n    |\n    = help: the following other types implement trait `IntoPropValue<T>`:\n              `yew::virtual_dom::VText` implements `IntoPropValue<ChildrenRenderer<VNode>>`\n              `yew::virtual_dom::VText` implements `IntoPropValue<VNode>`\nnote: required by a bound in `ChildContainerPropertiesBuilder::children`\n   --> tests/html_macro/component-fail.rs:24:17\n    |\n24  | #[derive(Clone, Properties, PartialEq)]\n    |                 ^^^^^^^^^^ required by this bound in `ChildContainerPropertiesBuilder::children`\n25  | pub struct ChildContainerProperties {\n26  |     pub children: ChildrenWithProps<Child>,\n    |         -------- required by a bound in this associated function\n    = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `VChild<Child>: From<yew::virtual_dom::VList>` is not satisfied\n   --> tests/html_macro/component-fail.rs:118:29\n    |\n118 |     html! { <ChildContainer><></></ChildContainer> };\n    |                             ^ the trait `From<yew::virtual_dom::VList>` is not implemented for `VChild<Child>`\n    |\n    = note: required for `yew::virtual_dom::VList` to implement `Into<VChild<Child>>`\n\nerror[E0277]: the trait bound `VNode: IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not satisfied\n   --> tests/html_macro/component-fail.rs:119:30\n    |\n119 |     html! { <ChildContainer><other /></ChildContainer> };\n    |              --------------  ^^^^^ the trait `IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not implemented for `VNode`\n    |              |\n    |              required by a bound introduced by this call\n    |\n    = help: the trait `IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not implemented for `VNode`\n            but trait `IntoPropValue<ChildrenRenderer<VNode>>` is implemented for it\n    = help: for that trait implementation, expected `VNode`, found `VChild<Child>`\nnote: required by a bound in `ChildContainerPropertiesBuilder::children`\n   --> tests/html_macro/component-fail.rs:24:17\n    |\n24  | #[derive(Clone, Properties, PartialEq)]\n    |                 ^^^^^^^^^^ required by this bound in `ChildContainerPropertiesBuilder::children`\n25  | pub struct ChildContainerProperties {\n26  |     pub children: ChildrenWithProps<Child>,\n    |         -------- required by a bound in this associated function\n    = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nwarning: unused variable: `props`\n   --> tests/html_macro/component-fail.rs:144:16\n    |\n144 | fn HtmlInProps(props: &HtmlInPropsProperties) -> Html { let _ = (); unimplemented!() }\n    |                ^^^^^ help: if this is intentional, prefix it with an underscore: `_props`\n    |\n    = note: `#[warn(unused_variables)]` on by default\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/component-pass.rs",
    "content": "// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct ContainerProperties {\n    pub int: ::std::primitive::i32,\n    #[prop_or_default]\n    pub children: ::yew::Children,\n    #[prop_or_default]\n    pub header: ::yew::Html,\n}\n\npub struct Container;\nimpl ::yew::Component for Container {\n    type Message = ();\n    type Properties = ContainerProperties;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\n#[derive(::std::clone::Clone, ::implicit_clone::ImplicitClone, ::std::cmp::PartialEq)]\npub enum ChildrenVariants {\n    Child(::yew::virtual_dom::VChild<Child>),\n    AltChild(::yew::virtual_dom::VChild<AltChild>),\n}\n\nimpl ::std::convert::From<::yew::virtual_dom::VChild<Child>> for ChildrenVariants {\n    fn from(comp: ::yew::virtual_dom::VChild<Child>) -> Self {\n        ChildrenVariants::Child(comp)\n    }\n}\n\nimpl ::std::convert::From<::yew::virtual_dom::VChild<AltChild>> for ChildrenVariants {\n    fn from(comp: ::yew::virtual_dom::VChild<AltChild>) -> Self {\n        ChildrenVariants::AltChild(comp)\n    }\n}\n\nimpl ::std::convert::Into<::yew::virtual_dom::VNode> for ChildrenVariants {\n    fn into(self) -> ::yew::virtual_dom::VNode {\n        match self {\n            Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::<\n                ::yew::virtual_dom::VComp,\n            >::into(comp))),\n            Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::<\n                ::yew::virtual_dom::VComp,\n            >::into(comp))),\n        }\n    }\n}\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct ChildProperties {\n    #[prop_or_default]\n    pub string: ::std::string::String,\n    #[prop_or_default]\n    pub r#fn: ::std::primitive::i32,\n    #[prop_or_default]\n    pub r#ref: ::yew::NodeRef,\n    pub int: ::std::primitive::i32,\n    #[prop_or_default]\n    pub opt_str: ::std::option::Option<::std::string::String>,\n    #[prop_or_default]\n    pub vec: ::std::vec::Vec<::std::primitive::i32>,\n    #[prop_or_default]\n    pub optional_callback: ::std::option::Option<::yew::Callback<()>>,\n}\n\npub struct Child;\nimpl ::yew::Component for Child {\n    type Message = ();\n    type Properties = ChildProperties;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\npub struct AltChild;\nimpl ::yew::Component for AltChild {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct ChildContainerProperties {\n    pub int: ::std::primitive::i32,\n    #[prop_or_default]\n    pub children: ::yew::html::ChildrenRenderer<ChildrenVariants>,\n}\n\npub struct ChildContainer;\nimpl ::yew::Component for ChildContainer {\n    type Message = ();\n    type Properties = ChildContainerProperties;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\nmod scoped {\n    pub use super::{Child, Container};\n}\n\nfn compile_pass() {\n    _ = ::yew::html! { <Child int=1 /> };\n    _ = ::yew::html! { <Child int=1 r#fn=1 /> };\n\n    _ = ::yew::html! {\n        <>\n            <Child int=1 />\n            <scoped::Child int=1 />\n        </>\n    };\n\n    let props = <<Child as ::yew::Component>::Properties as ::std::default::Default>::default();\n    let node_ref = <::yew::NodeRef as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Child ..::std::clone::Clone::clone(&props) />\n            <Child int={1} ..props />\n            <Child r#ref={::std::clone::Clone::clone(&node_ref)} int={2} ..::yew::props!(Child::Properties { int: 5 }) />\n            <Child int=3 r#ref={::std::clone::Clone::clone(&node_ref)} ..::yew::props!(Child::Properties { int: 5 }) />\n            <Child r#ref={::std::clone::Clone::clone(&node_ref)} ..::yew::props!(Child::Properties { int: 5 }) />\n            <Child r#ref={&node_ref} ..<<Child as ::yew::Component>::Properties as ::std::default::Default>::default() />\n            <Child r#ref={node_ref} ..<<Child as ::yew::Component>::Properties as ::std::default::Default>::default() />\n        </>\n    };\n\n    _ = ::yew::html! {\n        <>\n            <Child int=1 string=\"child\" />\n            <Child int=1 />\n            <Child int={1+1} />\n            <Child int=1 vec={::std::vec![1]} />\n            <Child string={<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from(\"child\")} int=1 />\n\n            <Child opt_str=\"child\" int=1 />\n            <Child opt_str={<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from(\"child\")} int=1 />\n            <Child opt_str={::std::option::Option::Some(\"child\")} int=1 />\n            <Child opt_str={::std::option::Option::Some(<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from(\"child\"))} int=1 />\n        </>\n    };\n\n    let name_expr = \"child\";\n    _ = ::yew::html! {\n        <Child int=1 string={name_expr} />\n    };\n\n    let string = \"child\";\n    let int = 1;\n    _ = ::yew::html! {\n        <Child {int} {string} />\n    };\n\n    _ = ::yew::html! {\n        <>\n            <Child int=1 />\n            <Child int=1 optional_callback={::std::option::Option::Some(<::yew::Callback<()> as ::std::convert::From<_>>::from(|_| ()))} />\n            <Child int=1 optional_callback={<::yew::Callback<()> as ::std::convert::From<_>>::from(|_| ())} />\n            <Child int=1 optional_callback={::std::option::Option::None::<::yew::Callback<_>>} />\n        </>\n    };\n\n    let node_ref = <::yew::NodeRef as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Child int=1 r#ref={node_ref} />\n        </>\n    };\n\n    let int = 1;\n    let node_ref = <::yew::NodeRef as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Child {int} r#ref={node_ref} />\n        </>\n    };\n\n    let props = <<Container as ::yew::Component>::Properties as ::std::default::Default>::default();\n    let child_props =\n        <<Child as ::yew::Component>::Properties as ::std::default::Default>::default();\n    _ = ::yew::html! {\n        <>\n            <Container int=1 />\n            <Container int=1></Container>\n\n            <Container ..::std::clone::Clone::clone(&props)>\n                <div>{ \"hello world\" }</div>\n            </Container>\n\n            <Container int=1 ..::std::clone::Clone::clone(&props)>\n                <div>{ \"hello world\" }</div>\n            </Container>\n\n            <Container int=1 ..::std::clone::Clone::clone(&props)>\n                <Child int=2 opt_str=\"hello\" ..::std::clone::Clone::clone(&child_props) />\n            </Container>\n\n            <Container int=1 ..::std::clone::Clone::clone(&props)>\n                <Child int=2 vec={::std::vec![0]} ..::std::clone::Clone::clone(&child_props) />\n            </Container>\n\n\n            <Container int=1 ..props>\n                <Child int=2 string=\"hello\" ..child_props />\n            </Container>\n\n            <Container int=1>\n                <Child int=2 />\n            </Container>\n\n            <scoped::Container int=1>\n                <scoped::Container int=2/>\n            </scoped::Container>\n\n            <Container int=1 children={::yew::html::ChildrenRenderer::new(\n                ::std::vec![::yew::html!{ \"::std::string::String\" }]\n            )} />\n            <Container int=1 header={::yew::html!{\n                <Child int=2 />\n            }} />\n        </>\n    };\n\n    _ = ::yew::html! {\n        <>\n            <ChildContainer int=1 />\n            <ChildContainer int=1></ChildContainer>\n            <ChildContainer int=1><Child int = 2 /></ChildContainer>\n            <ChildContainer int=1><Child int = 2 /><Child int = 2 /></ChildContainer>\n        </>\n    };\n\n    _ = ::yew::html! {\n        <ChildContainer int=1>\n            <AltChild />\n            <Child int=1 />\n            {\n                ::yew::html_nested! {\n                    <Child int=1 />\n                }\n            }\n            {\n                ::std::iter::Iterator::collect::<::std::vec::Vec<_>>(\n                    ::std::iter::Iterator::map(0..2,\n                        |i| { ::yew::html_nested! { <Child int={i} /> } })\n                )\n            }\n        </ChildContainer>\n    };\n\n    let children = ::std::vec![\n        ::yew::html_nested! { <Child int=1 /> },\n        ::yew::html_nested! { <Child int=2 /> },\n    ];\n    _ = ::yew::html! {\n        <ChildContainer int=1>\n            { ::std::clone::Clone::clone(&children) }\n        </ChildContainer>\n    };\n    // https://github.com/yewstack/yew/issues/1527\n    _ = ::yew::html! {\n        <ChildContainer int=1>\n            { for children }\n        </ChildContainer>\n    };\n\n    let variants = || -> ::std::vec::Vec<ChildrenVariants> {\n        ::std::vec![\n            ChildrenVariants::Child(::yew::virtual_dom::VChild::new(\n                <ChildProperties as ::std::default::Default>::default(),\n                ::std::option::Option::None,\n            )),\n            ChildrenVariants::AltChild(::yew::virtual_dom::VChild::new(\n                (),\n                ::std::option::Option::None\n            )),\n        ]\n    };\n\n    _ = ::yew::html! {\n        <>\n            {\n                ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(\n                    ::std::iter::Iterator::filter(\n                        ::std::iter::IntoIterator::into_iter(variants()),\n                        |c| match c {\n                            ChildrenVariants::Child(_) => true,\n                            _ => false,\n                        }\n                    )\n                )\n            }\n            <div>\n                {\n                    ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(\n                        ::std::iter::Iterator::filter(\n                            ::std::iter::IntoIterator::into_iter(variants()),\n                            |c| match c {\n                                ChildrenVariants::AltChild(_) => true,\n                                _ => false,\n                            }\n                        )\n                    )\n                }\n            </div>\n        </>\n    };\n\n    _ = ::yew::html_nested! { 1 };\n}\n\n#[derive(\n    ::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,\n)]\npub struct HtmlPassedAsPropProperties {\n    pub value: ::yew::Html,\n}\n\npub struct HtmlPassedAsProp;\nimpl ::yew::Component for HtmlPassedAsProp {\n    type Message = ();\n    type Properties = HtmlPassedAsPropProperties;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\npub struct HtmlPassedAsPropContainer;\nimpl ::yew::Component for HtmlPassedAsPropContainer {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::yew::html! {\n            <>\n            <HtmlPassedAsProp value={::yew::html!()} />\n            <HtmlPassedAsProp value=\"string literal\" />\n            <HtmlPassedAsProp value={::std::format!(\"string\")} />\n            <HtmlPassedAsProp value={::yew::AttrValue::Static(\"attr value\")} />\n            </>\n        }\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/component-unimplemented-fail.rs",
    "content": "use yew::prelude::*;\n\nstruct Unimplemented;\n\nfn compile_fail() {\n    html! { <Unimplemented /> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/component-unimplemented-fail.stderr",
    "content": "error[E0277]: the trait bound `Unimplemented: yew::Component` is not satisfied\n --> tests/html_macro/component-unimplemented-fail.rs:6:14\n  |\n6 |     html! { <Unimplemented /> };\n  |              ^^^^^^^^^^^^^ the trait `yew::Component` is not implemented for `Unimplemented`\n  |\n  = help: the trait `yew::Component` is implemented for `ContextProvider<T>`\n  = note: required for `Unimplemented` to implement `BaseComponent`\n  = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0599]: the function or associated item `new` exists for struct `VChild<Unimplemented>`, but its trait bounds were not satisfied\n --> tests/html_macro/component-unimplemented-fail.rs:6:14\n  |\n3 | struct Unimplemented;\n  | -------------------- doesn't satisfy `Unimplemented: BaseComponent` or `Unimplemented: yew::Component`\n...\n6 |     html! { <Unimplemented /> };\n  |              ^^^^^^^^^^^^^ function or associated item cannot be called on `VChild<Unimplemented>` due to unsatisfied trait bounds\n  |\n  = note: the following trait bounds were not satisfied:\n          `Unimplemented: yew::Component`\n          which is required by `Unimplemented: BaseComponent`\nnote: the trait `yew::Component` must be implemented\n --> $WORKSPACE/packages/yew/src/html/component/mod.rs\n  |\n  | pub trait Component: Sized + 'static {\n  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/dyn-element-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn main() {\n    let dyn_tag = || ::std::string::ToString::to_string(\"test\");\n    let mut next_extra_tag = {\n        let mut it = ::std::iter::IntoIterator::into_iter(::std::vec![\"a\", \"b\"]);\n        move || ::std::option::Option::unwrap(::std::iter::Iterator::next(&mut it))\n    };\n\n    _ = ::yew::html! {\n        <@{ dyn_tag() }>\n            <@{ next_extra_tag() } class=\"extra-a\"/>\n            <@{ next_extra_tag() } class=\"extra-b\"/>\n        </@>\n    };\n\n    _ = ::yew::html! {\n        <@{\n            if dyn_tag() == \"test\" {\n                \"div\"\n            } else {\n                \"a\"\n            }\n        }/>\n    };\n\n    let input_tag = \"input\";\n    let input_dom = ::yew::html! { <@{input_tag} /> };\n    assert!(\n        ::std::matches!(input_dom, ::yew::virtual_dom::VNode::VTag(ref vtag) if vtag.tag() == \"input\")\n    );\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/element-fail.rs",
    "content": "use yew::prelude::*;\n\nstruct NotToString;\n\nfn compile_fail() {\n    // missing closing tag\n    html! { <div> };\n    html! { <div><div> };\n    html! { <div><div></div> };\n\n    // missing opening tag\n    html! { </div> };\n    html! { <div></span></div> };\n    html! { <img /></img> };\n\n    // tag mismatch\n    html! { <div></span> };\n    html! { <tag-a></tag-b> };\n\n    // multiple root\n    html! { <div></div><div></div> };\n    // invalid child content\n    html! { <div>Invalid</div> };\n\n    // same attribute specified multiple times (tests for attributes with special treatment)\n    html! { <input attr=1 attr=2 /> };\n    html! { <input value=\"123\" value=\"456\" /> };\n    html! { <input kind=\"checkbox\" kind=\"submit\" /> };\n    html! { <input checked=true checked=false /> };\n    html! { <input disabled=true disabled=false /> };\n    html! { <option selected=true selected=false /> };\n    html! { <div class=\"first\" class=\"second\" /> };\n    html! { <input ref={()} ref={()} /> };\n\n    // boolean attribute type mismatch\n    html! { <input checked=1 /> };\n    html! { <input checked={Some(false)} /> };\n    html! { <input disabled=1 /> };\n    html! { <input disabled={Some(true)} /> };\n    html! { <option selected=1 /> };\n\n    // normal attribute type mismatch\n    html! { <input type={()} /> };\n    html! { <input value={()} /> };\n    html! { <a href={()} /> };\n    html! { <input string={NotToString} /> };\n    html! { <a media={Some(NotToString)} /> };\n    html! { <a href={Some(5)} /> };\n\n    // listener type mismatch\n    html! { <input onclick=1 /> };\n    html! { <input onclick={Callback::from(|a: String| ())} /> };\n    html! { <input onfocus={Some(5)} /> };\n\n    // NodeRef type mismatch\n    html! { <input ref={()} /> };\n    html! { <input ref={Some(NodeRef::default())} /> };\n    html! { <input onclick={Callback::from(|a: String| ())} /> };\n\n    html! { <input string={NotToString} /> };\n\n    html! { <input ref={()} /> };\n    html! { <input ref={()} ref={()} /> };\n\n    // void element with children\n    html! { <input type=\"text\"></input> };\n    // <textarea> should have a custom error message explaining how to set its default value\n    html! { <textarea>{\"default value\"}</textarea> }\n    // make sure that capitalization doesn't matter for the void children check\n    html! { <iNpUt type=\"text\"></iNpUt> };\n\n    // no tag name\n    html! { <@></@> };\n    html! { <@/> };\n\n    // invalid closing tag\n    html! { <@{\"test\"}></@{\"test\"}> };\n    // type mismatch\n    html! { <@{55}></@> };\n\n    // Missing curly braces\n    html! { <input ref=() /> };\n    html! { <input ref=() ref=() /> };\n    html! { <input onfocus=Some(5) /> };\n    html! { <input string=NotToString /> };\n    html! { <a media=Some(NotToString) /> };\n    html! { <a href=Some(5) /> };\n    html! { <input type=() /> };\n    html! { <input value=() /> };\n    html! { <input string=NotToString /> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/element-fail.stderr",
    "content": "error: this opening tag has no corresponding closing tag\n --> tests/html_macro/element-fail.rs:7:13\n  |\n7 |     html! { <div> };\n  |             ^^^^^\n\nerror: this opening tag has no corresponding closing tag\n --> tests/html_macro/element-fail.rs:8:18\n  |\n8 |     html! { <div><div> };\n  |                  ^^^^^\n\nerror: this opening tag has no corresponding closing tag\n --> tests/html_macro/element-fail.rs:9:13\n  |\n9 |     html! { <div><div></div> };\n  |             ^^^^^\n\nerror: this closing tag has no corresponding opening tag\n  --> tests/html_macro/element-fail.rs:12:13\n   |\n12 |     html! { </div> };\n   |             ^^^^^^\n\nerror: this closing tag has no corresponding opening tag\n  --> tests/html_macro/element-fail.rs:13:18\n   |\n13 |     html! { <div></span></div> };\n   |                  ^^^^^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n  --> tests/html_macro/element-fail.rs:14:20\n   |\n14 |     html! { <img /></img> };\n   |                    ^^^^^^\n\nerror: this closing tag has no corresponding opening tag\n  --> tests/html_macro/element-fail.rs:17:18\n   |\n17 |     html! { <div></span> };\n   |                  ^^^^^^^\n\nerror: this closing tag has no corresponding opening tag\n  --> tests/html_macro/element-fail.rs:18:20\n   |\n18 |     html! { <tag-a></tag-b> };\n   |                    ^^^^^^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n  --> tests/html_macro/element-fail.rs:21:24\n   |\n21 |     html! { <div></div><div></div> };\n   |                        ^^^^^^^^^^^\n\nerror: expected a valid html element\n  --> tests/html_macro/element-fail.rs:23:18\n   |\n23 |     html! { <div>Invalid</div> };\n   |                  ^^^^^^^\n\nerror: `attr` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:26:27\n   |\n26 |     html! { <input attr=1 attr=2 /> };\n   |                           ^^^^\n\nerror: `value` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:27:32\n   |\n27 |     html! { <input value=\"123\" value=\"456\" /> };\n   |                                ^^^^^\n\nerror: `kind` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:28:36\n   |\n28 |     html! { <input kind=\"checkbox\" kind=\"submit\" /> };\n   |                                    ^^^^\n\nerror: `checked` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:29:33\n   |\n29 |     html! { <input checked=true checked=false /> };\n   |                                 ^^^^^^^\n\nerror: `disabled` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:30:34\n   |\n30 |     html! { <input disabled=true disabled=false /> };\n   |                                  ^^^^^^^^\n\nerror: `selected` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:31:35\n   |\n31 |     html! { <option selected=true selected=false /> };\n   |                                   ^^^^^^^^\n\nerror: `class` can only be specified once but is given here again\n  --> tests/html_macro/element-fail.rs:32:32\n   |\n32 |     html! { <div class=\"first\" class=\"second\" /> };\n   |                                ^^^^^\n\nerror: `ref` can only be specified once\n  --> tests/html_macro/element-fail.rs:33:29\n   |\n33 |     html! { <input ref={()} ref={()} /> };\n   |                             ^^^\n\nerror: `ref` can only be specified once\n  --> tests/html_macro/element-fail.rs:63:29\n   |\n63 |     html! { <input ref={()} ref={()} /> };\n   |                             ^^^\n\nerror: the tag `<input>` is a void element and cannot have children (hint: rewrite this as `<input />`)\n  --> tests/html_macro/element-fail.rs:66:13\n   |\n66 |     html! { <input type=\"text\"></input> };\n   |             ^^^^^^^^^^^^^^^^^^^\n\nerror: the tag `<textarea>` is a void element and cannot have children (hint: to provide value to it, rewrite it as `<textarea value={x} />`. If you wish to set the default value, rewrite it as `<textarea defaultvalue={x} />`)\n  --> tests/html_macro/element-fail.rs:68:13\n   |\n68 |     html! { <textarea>{\"default value\"}</textarea> }\n   |             ^^^^^^^^^^\n\nerror: the tag `<iNpUt>` is a void element and cannot have children (hint: rewrite this as `<iNpUt />`)\n  --> tests/html_macro/element-fail.rs:70:13\n   |\n70 |     html! { <iNpUt type=\"text\"></iNpUt> };\n   |             ^^^^^^^^^^^^^^^^^^^\n\nerror: this dynamic tag is missing an expression block defining its value\n  --> tests/html_macro/element-fail.rs:73:14\n   |\n73 |     html! { <@></@> };\n   |              ^\n\nerror: this dynamic tag is missing an expression block defining its value\n  --> tests/html_macro/element-fail.rs:74:14\n   |\n74 |     html! { <@/> };\n   |              ^\n\nerror: dynamic closing tags must not have a body (hint: replace it with just `</@>`)\n  --> tests/html_macro/element-fail.rs:77:27\n   |\n77 |     html! { <@{\"test\"}></@{\"test\"}> };\n   |                           ^^^^^^^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple {\n           attrs: [],\n           paren_token: Paren,\n           elems: [],\n       }\n  --> tests/html_macro/element-fail.rs:82:24\n   |\n82 |     html! { <input ref=() /> };\n   |                        ^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple {\n           attrs: [],\n           paren_token: Paren,\n           elems: [],\n       }\n  --> tests/html_macro/element-fail.rs:83:24\n   |\n83 |     html! { <input ref=() ref=() /> };\n   |                        ^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Call {\n           attrs: [],\n           func: Expr::Path {\n               attrs: [],\n               qself: None,\n               path: Path {\n                   leading_colon: None,\n                   segments: [\n                       PathSegment {\n                           ident: Ident {\n                               ident: \"Some\",\n                               span: #0 bytes(2628..2632),\n                           },\n                           arguments: PathArguments::None,\n                       },\n                   ],\n               },\n           },\n           paren_token: Paren,\n           args: [\n               Expr::Lit {\n                   attrs: [],\n                   lit: Lit::Int {\n                       token: 5,\n                   },\n               },\n           ],\n       }\n  --> tests/html_macro/element-fail.rs:84:28\n   |\n84 |     html! { <input onfocus=Some(5) /> };\n   |                            ^^^^^^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Path {\n           attrs: [],\n           qself: None,\n           path: Path {\n               leading_colon: None,\n               segments: [\n                   PathSegment {\n                       ident: Ident {\n                           ident: \"NotToString\",\n                           span: #0 bytes(2668..2679),\n                       },\n                       arguments: PathArguments::None,\n                   },\n               ],\n           },\n       }\n  --> tests/html_macro/element-fail.rs:85:27\n   |\n85 |     html! { <input string=NotToString /> };\n   |                           ^^^^^^^^^^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Call {\n           attrs: [],\n           func: Expr::Path {\n               attrs: [],\n               qself: None,\n               path: Path {\n                   leading_colon: None,\n                   segments: [\n                       PathSegment {\n                           ident: Ident {\n                               ident: \"Some\",\n                               span: #0 bytes(2707..2711),\n                           },\n                           arguments: PathArguments::None,\n                       },\n                   ],\n               },\n           },\n           paren_token: Paren,\n           args: [\n               Expr::Path {\n                   attrs: [],\n                   qself: None,\n                   path: Path {\n                       leading_colon: None,\n                       segments: [\n                           PathSegment {\n                               ident: Ident {\n                                   ident: \"NotToString\",\n                                   span: #0 bytes(2712..2723),\n                               },\n                               arguments: PathArguments::None,\n                           },\n                       ],\n                   },\n               },\n           ],\n       }\n  --> tests/html_macro/element-fail.rs:86:22\n   |\n86 |     html! { <a media=Some(NotToString) /> };\n   |                      ^^^^^^^^^^^^^^^^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Call {\n           attrs: [],\n           func: Expr::Path {\n               attrs: [],\n               qself: None,\n               path: Path {\n                   leading_colon: None,\n                   segments: [\n                       PathSegment {\n                           ident: Ident {\n                               ident: \"Some\",\n                               span: #0 bytes(2751..2755),\n                           },\n                           arguments: PathArguments::None,\n                       },\n                   ],\n               },\n           },\n           paren_token: Paren,\n           args: [\n               Expr::Lit {\n                   attrs: [],\n                   lit: Lit::Int {\n                       token: 5,\n                   },\n               },\n           ],\n       }\n  --> tests/html_macro/element-fail.rs:87:21\n   |\n87 |     html! { <a href=Some(5) /> };\n   |                     ^^^^^^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple {\n           attrs: [],\n           paren_token: Paren,\n           elems: [],\n       }\n  --> tests/html_macro/element-fail.rs:88:25\n   |\n88 |     html! { <input type=() /> };\n   |                         ^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple {\n           attrs: [],\n           paren_token: Paren,\n           elems: [],\n       }\n  --> tests/html_macro/element-fail.rs:89:26\n   |\n89 |     html! { <input value=() /> };\n   |                          ^^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Path {\n           attrs: [],\n           qself: None,\n           path: Path {\n               leading_colon: None,\n               segments: [\n                   PathSegment {\n                       ident: Ident {\n                           ident: \"NotToString\",\n                           span: #0 bytes(2858..2869),\n                       },\n                       arguments: PathArguments::None,\n                   },\n               ],\n           },\n       }\n  --> tests/html_macro/element-fail.rs:90:27\n   |\n90 |     html! { <input string=NotToString /> };\n   |                           ^^^^^^^^^^^\n\nerror[E0308]: mismatched types\n  --> tests/html_macro/element-fail.rs:36:28\n   |\n36 |     html! { <input checked=1 /> };\n   |     -----------------------^-----\n   |     |                      |\n   |     |                      expected `bool`, found integer\n   |     arguments to this enum variant are incorrect\n   |\nhelp: the type constructed contains `{integer}` due to the type of the argument passed\n  --> tests/html_macro/element-fail.rs:36:5\n   |\n36 |     html! { <input checked=1 /> };\n   |     ^^^^^^^^^^^^^^^^^^^^^^^-^^^^^\n   |                            |\n   |                            this argument influences the type of `{{root}}`\nnote: tuple variant defined here\n  --> $RUST/core/src/option.rs\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0308]: mismatched types\n  --> tests/html_macro/element-fail.rs:37:29\n   |\n37 |     html! { <input checked={Some(false)} /> };\n   |     ------------------------^^^^^^^^^^^------\n   |     |                       |\n   |     |                       expected `bool`, found `Option<bool>`\n   |     arguments to this enum variant are incorrect\n   |\n   = note: expected type `bool`\n              found enum `Option<bool>`\nhelp: the type constructed contains `Option<bool>` due to the type of the argument passed\n  --> tests/html_macro/element-fail.rs:37:5\n   |\n37 |     html! { <input checked={Some(false)} /> };\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^\n   |                             |\n   |                             this argument influences the type of `{{root}}`\nnote: tuple variant defined here\n  --> $RUST/core/src/option.rs\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\nhelp: use `Option::is_some` to test if the `Option` has a value\n   |\n37 |     html! { <input checked={Some(false).is_some()} /> };\n   |                                        ++++++++++\n\nerror[E0308]: mismatched types\n  --> tests/html_macro/element-fail.rs:38:29\n   |\n38 |     html! { <input disabled=1 /> };\n   |                             ^\n   |                             |\n   |                             expected `bool`, found integer\n   |                             arguments to this function are incorrect\n   |\nnote: function defined here\n  --> $WORKSPACE/packages/yew/src/utils/mod.rs\n   |\n   | pub fn __ensure_type<T>(_: T) {}\n   |        ^^^^^^^^^^^^^\n\nerror[E0308]: mismatched types\n  --> tests/html_macro/element-fail.rs:39:30\n   |\n39 |     html! { <input disabled={Some(true)} /> };\n   |                              ^^^^^^^^^^ expected `bool`, found `Option<bool>`\n   |\n   = note: expected type `bool`\n              found enum `Option<bool>`\nhelp: use `Option::is_some` to test if the `Option` has a value\n   |\n39 |     html! { <input disabled={Some(true).is_some()} /> };\n   |                                        ++++++++++\n\nerror[E0308]: mismatched types\n  --> tests/html_macro/element-fail.rs:40:30\n   |\n40 |     html! { <option selected=1 /> };\n   |                              ^\n   |                              |\n   |                              expected `bool`, found integer\n   |                              arguments to this function are incorrect\n   |\nnote: function defined here\n  --> $WORKSPACE/packages/yew/src/utils/mod.rs\n   |\n   | pub fn __ensure_type<T>(_: T) {}\n   |        ^^^^^^^^^^^^^\n\nerror[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:43:26\n   |\n43 |     html! { <input type={()} /> };\n   |                          ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`\n   |\n   = help: the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`\n           but trait `IntoPropValue<VNode>` is implemented for it\n   = help: for that trait implementation, expected `VNode`, found `Option<implicit_clone::unsync::string::IString>`\n\nerror[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:44:27\n   |\n44 |     html! { <input value={()} /> };\n   |                           ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`\n   |\n   = help: the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`\n           but trait `IntoPropValue<VNode>` is implemented for it\n   = help: for that trait implementation, expected `VNode`, found `Option<implicit_clone::unsync::string::IString>`\n\nerror[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:45:22\n   |\n45 |     html! { <a href={()} /> };\n   |                      ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`\n   |\n   = help: the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`\n           but trait `IntoPropValue<VNode>` is implemented for it\n   = help: for that trait implementation, expected `VNode`, found `Option<implicit_clone::unsync::string::IString>`\n\nerror[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:46:28\n   |\n46 |     html! { <input string={NotToString} /> };\n   |                            ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `NotToString`\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `&&String` implements `IntoPropValue<Option<VNode>>`\n             `&&String` implements `IntoPropValue<VNode>`\n             `&&str` implements `IntoPropValue<Option<VNode>>`\n             `&&str` implements `IntoPropValue<VNode>`\n             `&'static [(K, V)]` implements `IntoPropValue<implicit_clone::unsync::map::IMap<K, V>>`\n             `&'static [T]` implements `IntoPropValue<implicit_clone::unsync::array::IArray<T>>`\n             `&'static str` implements `IntoPropValue<Classes>`\n             `&'static str` implements `IntoPropValue<Option<String>>`\n           and $N others\n\nerror[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:47:23\n   |\n47 |     html! { <a media={Some(NotToString)} /> };\n   |                       ----^^^^^^^^^^^^^\n   |                       |\n   |                       the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `Option<NotToString>`\n   |                       required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `Option<&String>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&implicit_clone::unsync::string::IString>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&str>` implements `IntoPropValue<Option<String>>`\n             `Option<&str>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&str>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`\n             `Option<Arc<String>>` implements `IntoPropValue<Option<VNode>>`\n             `Option<Arc<str>>` implements `IntoPropValue<Option<VNode>>`\n             `Option<Cow<'_, str>>` implements `IntoPropValue<Option<VNode>>`\n           and $N others\n\nerror[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:48:22\n   |\n48 |     html! { <a href={Some(5)} /> };\n   |                      ----^^^\n   |                      |\n   |                      the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `Option<{integer}>`\n   |                      required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `Option<&String>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&implicit_clone::unsync::string::IString>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&str>` implements `IntoPropValue<Option<String>>`\n             `Option<&str>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&str>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`\n             `Option<Arc<String>>` implements `IntoPropValue<Option<VNode>>`\n             `Option<Arc<str>>` implements `IntoPropValue<Option<VNode>>`\n             `Option<Cow<'_, str>>` implements `IntoPropValue<Option<VNode>>`\n           and $N others\n\nerror[E0277]: the trait bound `{integer}: IntoEventCallback<MouseEvent>` is not satisfied\n  --> tests/html_macro/element-fail.rs:51:28\n   |\n51 |     html! { <input onclick=1 /> };\n   |     -----------------------^-----\n   |     |                      |\n   |     |                      the trait `Fn(MouseEvent)` is not implemented for `{integer}`\n   |     required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoEventCallback<EVENT>`:\n             &yew::Callback<EVENT>\n             Option<T>\n             Option<yew::Callback<EVENT>>\n             yew::Callback<EVENT>\n   = note: required for `{integer}` to implement `IntoEventCallback<MouseEvent>`\nnote: required by a bound in `yew::html::onclick::Wrapper::__macro_new`\n  --> $WORKSPACE/packages/yew/src/html/listener/events.rs\n   |\n   | / impl_short! {\n   | |     onauxclick(MouseEvent)\n   | |     onclick(MouseEvent)\n...  |\n   | |     ontransitionstart(TransitionEvent)\n   | | }\n   | | ^\n   | | |\n   | |_required by a bound in this associated function\n   |   required by this bound in `Wrapper::__macro_new`\n   = note: this error originates in the macro `impl_action` which comes from the expansion of the macro `impl_short` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `yew::Callback<String>: IntoEventCallback<MouseEvent>` is not satisfied\n  --> tests/html_macro/element-fail.rs:52:29\n   |\n52 |     html! { <input onclick={Callback::from(|a: String| ())} /> };\n   |     ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------\n   |     |                       |\n   |     |                       the trait `Fn(MouseEvent)` is not implemented for `yew::Callback<String>`\n   |     required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoEventCallback<EVENT>`:\n             &yew::Callback<EVENT>\n             yew::Callback<EVENT>\n   = note: required for `yew::Callback<String>` to implement `IntoEventCallback<MouseEvent>`\nnote: required by a bound in `yew::html::onclick::Wrapper::__macro_new`\n  --> $WORKSPACE/packages/yew/src/html/listener/events.rs\n   |\n   | / impl_short! {\n   | |     onauxclick(MouseEvent)\n   | |     onclick(MouseEvent)\n...  |\n   | |     ontransitionstart(TransitionEvent)\n   | | }\n   | | ^\n   | | |\n   | |_required by a bound in this associated function\n   |   required by this bound in `Wrapper::__macro_new`\n   = note: this error originates in the macro `impl_action` which comes from the expansion of the macro `impl_short` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `Option<{integer}>: IntoEventCallback<FocusEvent>` is not satisfied\n  --> tests/html_macro/element-fail.rs:53:29\n   |\n53 |     html! { <input onfocus={Some(5)} /> };\n   |     ------------------------^^^^^^^------\n   |     |                       |\n   |     |                       the trait `IntoEventCallback<FocusEvent>` is not implemented for `Option<{integer}>`\n   |     required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoEventCallback<EVENT>`:\n             Option<T>\n             Option<yew::Callback<EVENT>>\nnote: required by a bound in `yew::html::onfocus::Wrapper::__macro_new`\n  --> $WORKSPACE/packages/yew/src/html/listener/events.rs\n   |\n   | / impl_short! {\n   | |     onauxclick(MouseEvent)\n   | |     onclick(MouseEvent)\n...  |\n   | |     ontransitionstart(TransitionEvent)\n   | | }\n   | | ^\n   | | |\n   | |_required by a bound in this associated function\n   |   required by this bound in `Wrapper::__macro_new`\n   = note: this error originates in the macro `impl_action` which comes from the expansion of the macro `impl_short` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied\n  --> tests/html_macro/element-fail.rs:56:25\n   |\n56 |     html! { <input ref={()} /> };\n   |                         ^^\n   |                         |\n   |                         the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`\n   |                         required by a bound introduced by this call\n   |\n   = help: the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`\n           but trait `IntoPropValue<VNode>` is implemented for it\n   = help: for that trait implementation, expected `VNode`, found `yew::NodeRef`\n\nerror[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>` is not satisfied\n  --> tests/html_macro/element-fail.rs:57:25\n   |\n57 |     html! { <input ref={Some(NodeRef::default())} /> };\n   |                         ----^^^^^^^^^^^^^^^^^^^^\n   |                         |\n   |                         the trait `IntoPropValue<yew::NodeRef>` is not implemented for `Option<yew::NodeRef>`\n   |                         required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `Option<&String>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&implicit_clone::unsync::string::IString>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&str>` implements `IntoPropValue<Option<String>>`\n             `Option<&str>` implements `IntoPropValue<Option<VNode>>`\n             `Option<&str>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`\n             `Option<Arc<String>>` implements `IntoPropValue<Option<VNode>>`\n             `Option<Arc<str>>` implements `IntoPropValue<Option<VNode>>`\n             `Option<Cow<'_, str>>` implements `IntoPropValue<Option<VNode>>`\n           and $N others\n\nerror[E0277]: the trait bound `yew::Callback<String>: IntoEventCallback<MouseEvent>` is not satisfied\n  --> tests/html_macro/element-fail.rs:58:29\n   |\n58 |     html! { <input onclick={Callback::from(|a: String| ())} /> };\n   |     ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------\n   |     |                       |\n   |     |                       the trait `Fn(MouseEvent)` is not implemented for `yew::Callback<String>`\n   |     required by a bound introduced by this call\n   |\n   = help: the following other types implement trait `IntoEventCallback<EVENT>`:\n             &yew::Callback<EVENT>\n             yew::Callback<EVENT>\n   = note: required for `yew::Callback<String>` to implement `IntoEventCallback<MouseEvent>`\nnote: required by a bound in `yew::html::onclick::Wrapper::__macro_new`\n  --> $WORKSPACE/packages/yew/src/html/listener/events.rs\n   |\n   | / impl_short! {\n   | |     onauxclick(MouseEvent)\n   | |     onclick(MouseEvent)\n...  |\n   | |     ontransitionstart(TransitionEvent)\n   | | }\n   | | ^\n   | | |\n   | |_required by a bound in this associated function\n   |   required by this bound in `Wrapper::__macro_new`\n   = note: this error originates in the macro `impl_action` which comes from the expansion of the macro `impl_short` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied\n  --> tests/html_macro/element-fail.rs:60:28\n   |\n60 |     html! { <input string={NotToString} /> };\n   |                            ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `NotToString`\n   |\n   = help: the following other types implement trait `IntoPropValue<T>`:\n             `&&String` implements `IntoPropValue<Option<VNode>>`\n             `&&String` implements `IntoPropValue<VNode>`\n             `&&str` implements `IntoPropValue<Option<VNode>>`\n             `&&str` implements `IntoPropValue<VNode>`\n             `&'static [(K, V)]` implements `IntoPropValue<implicit_clone::unsync::map::IMap<K, V>>`\n             `&'static [T]` implements `IntoPropValue<implicit_clone::unsync::array::IArray<T>>`\n             `&'static str` implements `IntoPropValue<Classes>`\n             `&'static str` implements `IntoPropValue<Option<String>>`\n           and $N others\n\nerror[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied\n  --> tests/html_macro/element-fail.rs:62:25\n   |\n62 |     html! { <input ref={()} /> };\n   |                         ^^\n   |                         |\n   |                         the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`\n   |                         required by a bound introduced by this call\n   |\n   = help: the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`\n           but trait `IntoPropValue<VNode>` is implemented for it\n   = help: for that trait implementation, expected `VNode`, found `yew::NodeRef`\n\nerror[E0277]: the trait bound `implicit_clone::unsync::string::IString: From<{integer}>` is not satisfied\n  --> tests/html_macro/element-fail.rs:79:16\n   |\n79 |     html! { <@{55}></@> };\n   |                ^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::string::IString`\n   |\n   = help: the following other types implement trait `From<T>`:\n             `implicit_clone::unsync::string::IString` implements `From<&Classes>`\n             `implicit_clone::unsync::string::IString` implements `From<&implicit_clone::unsync::string::IString>`\n             `implicit_clone::unsync::string::IString` implements `From<&str>`\n             `implicit_clone::unsync::string::IString` implements `From<Arguments<'_>>`\n             `implicit_clone::unsync::string::IString` implements `From<Cow<'_, str>>`\n             `implicit_clone::unsync::string::IString` implements `From<Rc<str>>`\n             `implicit_clone::unsync::string::IString` implements `From<String>`\n   = note: required for `{integer}` to implement `Into<implicit_clone::unsync::string::IString>`\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/for-fail.rs",
    "content": "mod smth {\n    const KEY: u32 = 42;\n}\n\nfn main() {\n    _ = ::yew::html!{for x};\n    _ = ::yew::html!{for x in};\n    _ = ::yew::html!{for x in 0 .. 10};\n    _ = ::yew::html!{for (x, y) in 0 .. 10 {\n        <span>{x}</span>\n    }};\n\n    _ = ::yew::html!{for _ in 0 .. 10 {\n        <span>{break}</span>\n    }};\n\n    _ = ::yew::html!{for _ in 0 .. 10 {\n        <div key=\"duplicate\" />\n    }};\n\n    _ = ::yew::html!{for _ in 0 .. 10 {\n        <div key={smth::KEY} />\n    }};\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/for-fail.stderr",
    "content": "error: unexpected end of input, expected `in`\n --> tests/html_macro/for-fail.rs:6:9\n  |\n6 |     _ = ::yew::html!{for x};\n  |         ^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `::yew::html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: unexpected end of input, expected an expression\n --> tests/html_macro/for-fail.rs:7:9\n  |\n7 |     _ = ::yew::html!{for x in};\n  |         ^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `::yew::html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: unexpected end of input, expected curly braces\n --> tests/html_macro/for-fail.rs:8:9\n  |\n8 |     _ = ::yew::html!{for x in 0 .. 10};\n  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `::yew::html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: duplicate key for a node in a `for`-loop\n       this will create elements with duplicate keys if the loop iterates more than once\n  --> tests/html_macro/for-fail.rs:18:18\n   |\n18 |         <div key=\"duplicate\" />\n   |                  ^^^^^^^^^^^\n\nerror: duplicate key for a node in a `for`-loop\n       this will create elements with duplicate keys if the loop iterates more than once\n  --> tests/html_macro/for-fail.rs:22:19\n   |\n22 |         <div key={smth::KEY} />\n   |                   ^^^^\n\nerror[E0267]: `break` inside of a closure\n  --> tests/html_macro/for-fail.rs:14:16\n   |\n13 |       _ = ::yew::html!{for _ in 0 .. 10 {\n   |  _________-\n14 | |         <span>{break}</span>\n   | |                ^^^^^ cannot `break` inside of a closure\n15 | |     }};\n   | |______- enclosing closure\n\nerror[E0308]: mismatched types\n --> tests/html_macro/for-fail.rs:9:26\n  |\n9 |     _ = ::yew::html!{for (x, y) in 0 .. 10 {\n  |                          ^^^^^^\n  |                          |\n  |                          expected integer, found `(_, _)`\n  |                          expected due to this\n  |\n  = note: expected type `{integer}`\n            found tuple `(_, _)`\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/for-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn main() {\n    _ = ::yew::html!{\n        for i in 0 .. 10 {\n            <span>{i}</span>\n        }\n    };\n\n    struct Pair {\n        value1: &'static ::std::primitive::str,\n        value2: ::std::primitive::i32\n    }\n\n    _ = ::yew::html! {\n        for Pair { value1, value2 } in ::std::iter::Iterator::map(0 .. 10, |value2| Pair { value1: \"Yew\", value2 }) {\n            <span>{value1}</span>\n            <span>{value2}</span>\n        }\n    };\n\n    fn rand_number() -> ::std::primitive::u32 {\n        4 // chosen by fair dice roll. guaranteed to be random.\n    }\n\n    _ = ::yew::html!{\n        for _ in 0..5 {\n            <div>\n                {{\n                    loop {\n                        let a = rand_number();\n                        if a % 2 == 0 {\n                            break a;\n                        }\n                    }\n                }}\n            </div>\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/generic-component-fail.rs",
    "content": "use std::marker::PhantomData;\r\nuse yew::prelude::*;\r\n\r\npub struct Generic<T> {\r\n    marker: PhantomData<T>,\r\n}\r\n\r\nimpl<T> Component for Generic<T>\r\nwhere\r\n    T: 'static,\r\n{\r\n    type Message = ();\r\n    type Properties = ();\r\n\r\n    fn create(_ctx: &Context<Self>) -> Self {\r\n        unimplemented!()\r\n    }\r\n    fn view(&self, _ctx: &Context<Self>) -> Html {\r\n        unimplemented!()\r\n    }\r\n}\r\n\r\npub struct Generic2<T1, T2> {\r\n    marker: PhantomData<(T1, T2)>,\r\n}\r\n\r\nimpl<T1, T2> Component for Generic2<T1, T2>\r\nwhere\r\n    T1: 'static,\r\n    T2: 'static,\r\n{\r\n    type Message = ();\r\n    type Properties = ();\r\n\r\n    fn create(_ctx: &Context<Self>) -> Self {\r\n        unimplemented!()\r\n    }\r\n    fn view(&self, _ctx: &Context<Self>) -> Html {\r\n        unimplemented!()\r\n    }}\r\n\r\nfn compile_fail() {\r\n    #[allow(unused_imports)]\r\n    use std::path::Path;\r\n\r\n    html! { <Generic<String>> };\r\n    html! { <Generic<String>></Generic> };\r\n    html! { <Generic<String>></Generic<Vec<String>>> };\r\n\r\n    html! { <Generic<String>></Generic<Path>> };\r\n    html! { <Generic<String>></> };\r\n}\r\n\r\nfn main() {}\r\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/generic-component-fail.stderr",
    "content": "error: this opening tag has no corresponding closing tag\n  --> tests/html_macro/generic-component-fail.rs:46:13\n   |\n46 |     html! { <Generic<String>> };\n   |             ^^^^^^^^^^^^^^^^^\n\nerror: mismatched closing tags: expected `Generic<String>`, found `Generic`\n  --> tests/html_macro/generic-component-fail.rs:47:14\n   |\n47 |     html! { <Generic<String>></Generic> };\n   |              ^^^^^^^^^^^^^^^^^^^^^^^^^\n\nerror: mismatched closing tags: expected `Generic<String>`, found `Generic<Vec<String>>`\n  --> tests/html_macro/generic-component-fail.rs:48:14\n   |\n48 |     html! { <Generic<String>></Generic<Vec<String>>> };\n   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nerror: mismatched closing tags: expected `Generic<String>`, found `Generic<Path>`\n  --> tests/html_macro/generic-component-fail.rs:50:14\n   |\n50 |     html! { <Generic<String>></Generic<Path>> };\n   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nerror: expected a valid closing tag for component\n       note: found opening tag `<Generic<String>>`\n       help: try `</Generic<String>>`\n  --> tests/html_macro/generic-component-fail.rs:51:30\n   |\n51 |     html! { <Generic<String>></> };\n   |                              ^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/generic-component-pass.rs",
    "content": "#![no_implicit_prelude]\r\n\r\n// Shadow primitives\r\n#[allow(non_camel_case_types)]\r\npub struct bool;\r\n#[allow(non_camel_case_types)]\r\npub struct char;\r\n#[allow(non_camel_case_types)]\r\npub struct f32;\r\n#[allow(non_camel_case_types)]\r\npub struct f64;\r\n#[allow(non_camel_case_types)]\r\npub struct i128;\r\n#[allow(non_camel_case_types)]\r\npub struct i16;\r\n#[allow(non_camel_case_types)]\r\npub struct i32;\r\n#[allow(non_camel_case_types)]\r\npub struct i64;\r\n#[allow(non_camel_case_types)]\r\npub struct i8;\r\n#[allow(non_camel_case_types)]\r\npub struct isize;\r\n#[allow(non_camel_case_types)]\r\npub struct str;\r\n#[allow(non_camel_case_types)]\r\npub struct u128;\r\n#[allow(non_camel_case_types)]\r\npub struct u16;\r\n#[allow(non_camel_case_types)]\r\npub struct u32;\r\n#[allow(non_camel_case_types)]\r\npub struct u64;\r\n#[allow(non_camel_case_types)]\r\npub struct u8;\r\n#[allow(non_camel_case_types)]\r\npub struct usize;\r\n\r\npub struct Generic<T> {\r\n    marker: ::std::marker::PhantomData<T>,\r\n}\r\n\r\nimpl<T> ::yew::Component for Generic<T>\r\nwhere\r\n    T: 'static,\r\n{\r\n    type Message = ();\r\n    type Properties = ();\r\n\r\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\r\n        ::std::unimplemented!()\r\n    }\r\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\r\n        ::std::unimplemented!()\r\n    }\r\n}\r\n\r\npub struct Generic2<T1, T2> {\r\n    marker: ::std::marker::PhantomData<(T1, T2)>,\r\n}\r\n\r\nimpl<T1, T2> ::yew::Component for Generic2<T1, T2>\r\nwhere\r\n    T1: 'static,\r\n    T2: 'static,\r\n{\r\n    type Message = ();\r\n    type Properties = ();\r\n\r\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\r\n        ::std::unimplemented!()\r\n    }\r\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\r\n        ::std::unimplemented!()\r\n    }\r\n}\r\n\r\nfn compile_pass() {\r\n    _ = ::yew::html! { <Generic<::std::string::String> /> };\r\n    _ = ::yew::html! { <Generic<(u8, bool)> /> };\r\n    _ = ::yew::html! { <Generic<(u8, bool)> ></Generic<(u8, bool)>> };\r\n    _ = ::yew::html! { <Generic<::std::string::String> ></Generic<::std::string::String>> };\r\n\r\n    _ = ::yew::html! { <Generic<::std::vec::Vec<::std::string::String>> /> };\r\n    _ = ::yew::html! { <Generic<::std::vec::Vec<::std::string::String>>></ Generic<::std::vec::Vec<::std::string::String>>> };\r\n\r\n    _ = ::yew::html! { <Generic<::std::primitive::usize> /> };\r\n    _ = ::yew::html! { <Generic<::std::primitive::usize>></Generic<::std::primitive::usize>> };\r\n    _ = ::yew::html! { <Generic<::std::string::String, > /> };\r\n    _ = ::yew::html! { <Generic<::std::string::String, >></Generic<::std::string::String,>> };\r\n\r\n    _ = ::yew::html! { <Generic2<::std::string::String, ::std::string::String> /> };\r\n    _ = ::yew::html! { <Generic2<::std::string::String, ::std::string::String>></Generic2<::std::string::String, ::std::string::String>> };\r\n\r\n    _ = ::yew::html! { <Generic2<::std::string::String, ::std::string::String, > /> };\r\n    _ = ::yew::html! { <Generic2<::std::string::String, ::std::string::String, >></Generic2<::std::string::String, ::std::string::String, >> };\r\n}\r\n\r\nfn main() {}\r\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/html-component-fail.stderr",
    "content": "error: this opening tag has no corresponding closing tag\n  --> $DIR/html-component-fail.rs:78:13\n   |\n78 |     html! { <Child> };\n   |             ^^^^^^^\n\nerror: unexpected end of input, expected identifier\n  --> $DIR/html-component-fail.rs:79:13\n   |\n79 |     html! { <Child:: /> };\n   |             ^^^^^^^^^^^\n\nerror: expected expression following this `with`\n  --> $DIR/html-component-fail.rs:80:20\n   |\n80 |     html! { <Child with /> };\n   |                    ^^^^\n\nerror: `props` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)\n  --> $DIR/html-component-fail.rs:81:20\n   |\n81 |     html! { <Child props /> };\n   |                    ^^^^^\n\nerror: this opening tag has no corresponding closing tag\n  --> $DIR/html-component-fail.rs:82:13\n   |\n82 |     html! { <Child with props > };\n   |             ^^^^^^^^^^^^^^^^^^^\n\nerror: there are two `with <props>` definitions for this component (note: you can only define `with <props>` once)\n  --> $DIR/html-component-fail.rs:84:20\n   |\n84 |     html! { <Child with p1 with p2 /> };\n   |                    ^^^^^^^\n\nerror: `ref` can only be set once\n  --> $DIR/html-component-fail.rs:85:38\n   |\n85 |     html! { <Child with props ref=() ref=() /> };\n   |                                      ^^^\n\nerror: `ref` can only be set once\n  --> $DIR/html-component-fail.rs:86:38\n   |\n86 |     html! { <Child with props ref=() ref=() value=1 /> };\n   |                                      ^^^\n\nerror: Using the `with props` syntax in combination with named props is not allowed (note: this does not apply to special props like `ref` and `key`)\n  --> $DIR/html-component-fail.rs:87:38\n   |\n87 |     html! { <Child with props ref=() value=1 ref=() /> };\n   |                                      ^^^^^\n\nerror: Using the `with props` syntax in combination with named props is not allowed (note: this does not apply to special props like `ref` and `key`)\n  --> $DIR/html-component-fail.rs:88:31\n   |\n88 |     html! { <Child with props value=1 ref=()  ref=() /> };\n   |                               ^^^^^\n\nerror: Using the `with props` syntax in combination with named props is not allowed (note: this does not apply to special props like `ref` and `key`)\n  --> $DIR/html-component-fail.rs:89:20\n   |\n89 |     html! { <Child value=1 with props  ref=()  ref=() /> };\n   |                    ^^^^^\n\nerror: Using the `with props` syntax in combination with named props is not allowed (note: this does not apply to special props like `ref` and `key`)\n  --> $DIR/html-component-fail.rs:90:20\n   |\n90 |     html! { <Child value=1 ref=() with props ref=() /> };\n   |                    ^^^^^\n\nerror: `ref` can only be set once\n  --> $DIR/html-component-fail.rs:91:27\n   |\n91 |     html! { <Child ref=() ref=() value=1  with props  /> };\n   |                           ^^^\n\nerror: Using the `with props` syntax in combination with named props is not allowed (note: this does not apply to special props like `ref` and `key`)\n  --> $DIR/html-component-fail.rs:93:20\n   |\n93 |     html! { <Child value=1 with props /> };\n   |                    ^^^^^\n\nerror: Using the `with props` syntax in combination with named props is not allowed (note: this does not apply to special props like `ref` and `key`)\n  --> $DIR/html-component-fail.rs:94:31\n   |\n94 |     html! { <Child with props value=1 /> };\n   |                               ^^^^^\n\nerror: expected identifier, found keyword `type`\n  --> $DIR/html-component-fail.rs:95:20\n   |\n95 |     html! { <Child type=0 /> };\n   |                    ^^^^ expected identifier, found keyword\n   |\nhelp: you can escape reserved keywords to use them as identifiers\n   |\n95 |     html! { <Child r#type=0 /> };\n   |                    ^^^^^^\n\nerror: expected a valid Rust identifier\n  --> $DIR/html-component-fail.rs:96:20\n   |\n96 |     html! { <Child invalid-prop-name=0 /> };\n   |                    ^^^^^^^^^^^^^^^^^\n\nerror: expected an expression following this equals sign\n  --> $DIR/html-component-fail.rs:98:26\n   |\n98 |     html! { <Child string= /> };\n   |                          ^\n\nerror: `int` can only be specified once but is given here again\n  --> $DIR/html-component-fail.rs:99:26\n   |\n99 |     html! { <Child int=1 int=2 int=3 /> };\n   |                          ^^^\n\nerror: `int` can only be specified once but is given here again\n  --> $DIR/html-component-fail.rs:99:32\n   |\n99 |     html! { <Child int=1 int=2 int=3 /> };\n   |                                ^^^\n\nerror: `ref` can only be specified once\n   --> $DIR/html-component-fail.rs:104:26\n    |\n104 |     html! { <Child int=1 ref=() ref=() /> };\n    |                          ^^^\n\nerror: this closing tag has no corresponding opening tag\n   --> $DIR/html-component-fail.rs:107:13\n    |\n107 |     html! { </Child> };\n    |             ^^^^^^^^\n\nerror: this opening tag has no corresponding closing tag\n   --> $DIR/html-component-fail.rs:108:13\n    |\n108 |     html! { <Child><Child></Child> };\n    |             ^^^^^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n   --> $DIR/html-component-fail.rs:109:28\n    |\n109 |     html! { <Child></Child><Child></Child> };\n    |                            ^^^^^^^^^^^^^^^\n\nerror: cannot specify the `children` prop when the component already has children\n   --> $DIR/html-component-fail.rs:128:25\n    |\n128 |         <ChildContainer children=children>\n    |                         ^^^^^^^^\n\nerror: this closing tag has no corresponding opening tag\n   --> $DIR/html-component-fail.rs:133:30\n    |\n133 |     html! { <Generic<String>></Generic> };\n    |                              ^^^^^^^^^^\n\nerror: this closing tag has no corresponding opening tag\n   --> $DIR/html-component-fail.rs:134:30\n    |\n134 |     html! { <Generic<String>></Generic<Vec<String>>> };\n    |                              ^^^^^^^^^^^^^^^^^^^^^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n   --> $DIR/html-component-fail.rs:138:9\n    |\n138 |         <span>{ 2 }</span>\n    |         ^^^^^^^^^^^^^^^^^^\n\nerror: optional attributes are only supported on elements. Components can use `Option<T>` properties to accomplish the same thing.\n   --> $DIR/html-component-fail.rs:141:28\n    |\n141 |     html! { <TestComponent value?=\"not_supported\" /> };\n    |                            ^^^^^\n\nerror[E0425]: cannot find value `blah` in this scope\n  --> $DIR/html-component-fail.rs:92:25\n   |\n92 |     html! { <Child with blah /> };\n   |                         ^^^^ not found in this scope\n\nerror[E0609]: no field `r#type` on type `ChildProperties`\n  --> $DIR/html-component-fail.rs:95:20\n   |\n95 |     html! { <Child type=0 /> };\n   |                    ^^^^ unknown field\n   |\n   = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `r#type` found for struct `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope\n  --> $DIR/html-component-fail.rs:95:20\n   |\n5  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `r#type` not found for this\n...\n95 |     html! { <Child type=0 /> };\n   |                    ^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`\n\nerror[E0609]: no field `unknown` on type `ChildProperties`\n  --> $DIR/html-component-fail.rs:97:20\n   |\n97 |     html! { <Child unknown=\"unknown\" /> };\n   |                    ^^^^^^^ unknown field\n   |\n   = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `unknown` found for struct `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope\n  --> $DIR/html-component-fail.rs:97:20\n   |\n5  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `unknown` not found for this\n...\n97 |     html! { <Child unknown=\"unknown\" /> };\n   |                    ^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VComp: yew::virtual_dom::Transformer<(), std::string::String>` is not satisfied\n   --> $DIR/html-component-fail.rs:100:33\n    |\n100 |     html! { <Child int=1 string={} /> };\n    |                                 ^^ the trait `yew::virtual_dom::Transformer<(), std::string::String>` is not implemented for `yew::virtual_dom::vcomp::VComp`\n    |\n    = help: the following implementations were found:\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, T>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, std::option::Option<T>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::option::Option<std::string::String>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::string::String>>\n            and 3 others\n    = note: required by `yew::virtual_dom::Transformer::transform`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VComp: yew::virtual_dom::Transformer<{integer}, std::string::String>` is not satisfied\n   --> $DIR/html-component-fail.rs:101:33\n    |\n101 |     html! { <Child int=1 string=3 /> };\n    |                                 ^ the trait `yew::virtual_dom::Transformer<{integer}, std::string::String>` is not implemented for `yew::virtual_dom::vcomp::VComp`\n    |\n    = help: the following implementations were found:\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, T>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, std::option::Option<T>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::option::Option<std::string::String>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::string::String>>\n            and 3 others\n    = note: required by `yew::virtual_dom::Transformer::transform`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VComp: yew::virtual_dom::Transformer<{integer}, std::string::String>` is not satisfied\n   --> $DIR/html-component-fail.rs:102:33\n    |\n102 |     html! { <Child int=1 string={3} /> };\n    |                                 ^^^ the trait `yew::virtual_dom::Transformer<{integer}, std::string::String>` is not implemented for `yew::virtual_dom::vcomp::VComp`\n    |\n    = help: the following implementations were found:\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, T>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, std::option::Option<T>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::option::Option<std::string::String>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::string::String>>\n            and 3 others\n    = note: required by `yew::virtual_dom::Transformer::transform`\n\nerror[E0308]: mismatched types\n   --> $DIR/html-component-fail.rs:103:30\n    |\n103 |     html! { <Child int=1 ref=() /> };\n    |                              ^^ expected struct `yew::html::NodeRef`, found `()`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VComp: yew::virtual_dom::Transformer<u32, i32>` is not satisfied\n   --> $DIR/html-component-fail.rs:105:24\n    |\n105 |     html! { <Child int=0u32 /> };\n    |                        ^^^^ the trait `yew::virtual_dom::Transformer<u32, i32>` is not implemented for `yew::virtual_dom::vcomp::VComp`\n    |\n    = help: the following implementations were found:\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, T>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a T, std::option::Option<T>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::option::Option<std::string::String>>>\n              <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::Transformer<&'a str, std::string::String>>\n            and 3 others\n    = note: required by `yew::virtual_dom::Transformer::transform`\n\nerror[E0599]: no method named `string` found for struct `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope\n   --> $DIR/html-component-fail.rs:106:20\n    |\n5   | #[derive(Clone, Properties, PartialEq)]\n    |                 ---------- method `string` not found for this\n...\n106 |     html! { <Child string=\"abc\" /> };\n    |                    ^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`\n    |\n    = help: items from traits can only be used if the trait is implemented and in scope\n    = note: the following trait defines an item `string`, perhaps you need to implement it:\n            candidate #1: `proc_macro::bridge::server::Literal`\n\nerror[E0609]: no field `children` on type `ChildProperties`\n   --> $DIR/html-component-fail.rs:110:14\n    |\n110 |     html! { <Child>{ \"Not allowed\" }</Child> };\n    |              ^^^^^ unknown field\n    |\n    = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `children` found for struct `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope\n   --> $DIR/html-component-fail.rs:110:14\n    |\n5   | #[derive(Clone, Properties, PartialEq)]\n    |                 ---------- method `children` not found for this\n...\n110 |     html! { <Child>{ \"Not allowed\" }</Child> };\n    |              ^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`\n\nerror[E0609]: no field `children` on type `ChildProperties`\n   --> $DIR/html-component-fail.rs:114:10\n    |\n114 |         <Child with ChildProperties { string: \"hello\".to_owned(), int: 5 }>\n    |          ^^^^^ unknown field\n    |\n    = note: available fields are: `string`, `int`\n\nerror[E0599]: no method named `build` found for struct `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>` in the current scope\n   --> $DIR/html-component-fail.rs:119:14\n    |\n31  | #[derive(Clone, Properties)]\n    |                 ---------- method `build` not found for this\n...\n119 |     html! { <ChildContainer /> };\n    |              ^^^^^^^^^^^^^^ method not found in `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>`\n    |\n    = help: items from traits can only be used if the trait is implemented and in scope\n    = note: the following trait defines an item `build`, perhaps you need to implement it:\n            candidate #1: `proc_macro::bridge::server::TokenStreamBuilder`\n\nerror[E0599]: no method named `build` found for struct `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>` in the current scope\n   --> $DIR/html-component-fail.rs:120:14\n    |\n31  | #[derive(Clone, Properties)]\n    |                 ---------- method `build` not found for this\n...\n120 |     html! { <ChildContainer></ChildContainer> };\n    |              ^^^^^^^^^^^^^^ method not found in `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>`\n    |\n    = help: items from traits can only be used if the trait is implemented and in scope\n    = note: the following trait defines an item `build`, perhaps you need to implement it:\n            candidate #1: `proc_macro::bridge::server::TokenStreamBuilder`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vtext::VText>` is not satisfied\n   --> $DIR/html-component-fail.rs:121:31\n    |\n121 |     html! { <ChildContainer>{ \"Not allowed\" }</ChildContainer> };\n    |                               ^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vtext::VText>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`\n    |\n    = note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vtext::VText`\n    = note: required by `std::convert::Into::into`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied\n   --> $DIR/html-component-fail.rs:122:29\n    |\n122 |     html! { <ChildContainer><></></ChildContainer> };\n    |                             ^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`\n    |\n    = note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`\n    = note: required by `std::convert::Into::into`\n\nerror[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied\n   --> $DIR/html-component-fail.rs:123:30\n    |\n123 |     html! { <ChildContainer><other /></ChildContainer> };\n    |                              ^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`\n    |\n    = note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`\n    = note: required by `std::convert::Into::into`\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/html-element-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn compile_pass() {\n    let onclick = <::yew::Callback<::yew::events::MouseEvent> as ::std::convert::From<_>>::from(\n        |_: ::yew::events::MouseEvent| (),\n    );\n    let parent_ref = <::yew::NodeRef as ::std::default::Default>::default();\n\n    let dyn_tag =\n        || <::std::string::String as ::std::convert::From<&::std::primitive::str>>::from(\"test\");\n    let mut extra_tags_iter = ::std::iter::IntoIterator::into_iter(::std::vec![\"a\", \"b\"]);\n\n    let attr_val_none: ::std::option::Option<::yew::virtual_dom::AttrValue> = ::std::option::Option::None;\n\n    _ = ::yew::html! {\n        <div>\n            <div data-key=\"abc\"></div>\n            <div ref={&parent_ref}></div>\n            <div ref={parent_ref} class=\"parent\">\n                <span class=\"child\" value=\"anything\"></span>\n                <label for=\"first-name\">{\"First Name\"}</label>\n                <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n                <input type=\"checkbox\" checked=true />\n                <textarea value=\"write a story\" />\n                <select name=\"status\">\n                    <option selected=true disabled=false value=\"\">{\"Selected\"}</option>\n                    <option selected=false disabled=true value=\"\">{\"Unselected\"}</option>\n                </select>\n                <video autoplay=true controls=true />\n            </div>\n            <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n                <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n                <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n                <g filter=\"url(#filter0_d)\">\n                    <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n                    <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n                </g>\n                <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n                <defs>\n                    <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                        <feGaussianBlur stdDeviation=\"2\"/>\n                        <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n                    </filter>\n                </defs>\n            </svg>\n            <img class={::yew::classes!(\"avatar\", \"hidden\")} src=\"http://pic.com\" />\n            <img class=\"avatar hidden\" />\n            <button onclick={&onclick} {onclick} />\n            <a href=\"http://google.com\" />\n            <custom-tag-a>\n                <custom-tag-b />\n            </custom-tag-a>\n            <@{dyn_tag()}>\n                <@{::std::iter::Iterator::next(&mut extra_tags_iter).unwrap()} class=\"extra-a\"/>\n                <@{::std::iter::Iterator::next(&mut extra_tags_iter).unwrap()} class=\"extra-b\"/>\n            </@>\n\n            <@{\n                if dyn_tag() == \"test\" {\n                    \"div\"\n                } else {\n                    \"a\"\n                }\n            }/>\n\n            <a href={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static(\"http://google.com\"))} media={::std::clone::Clone::clone(&attr_val_none)} />\n            <track kind={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static(\"subtitles\"))} src={::std::clone::Clone::clone(&attr_val_none)} />\n            <track kind={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static(\"5\"))} mixed=\"works\" />\n            <input value={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static(\"value\"))}\n                onblur={::std::option::Option::Some(<::yew::Callback<::yew::FocusEvent> as ::std::convert::From<_>>::from(|_| ()))}\n            />\n        </div>\n    };\n\n    let children = ::std::vec![\n        ::yew::html! { <span>{ \"Hello\" }</span> },\n        ::yew::html! { <span>{ \"World\" }</span> },\n    ];\n    _ = ::yew::html! { <div>{children}</div> };\n\n    // handle misleading angle brackets\n    _ = ::yew::html! { <div data-val={<::std::string::String as ::std::default::Default>::default()}></div> };\n    _ = ::yew::html! { <div><a data-val={<::std::string::String as ::std::default::Default>::default()} /></div> };\n\n    // test for https://github.com/yewstack/yew/issues/2810\n    _ = ::yew::html! {  <div data-type=\"date\" data-as=\"calender\" /> };\n\n    let option_vnode = ::std::option::Option::Some(::yew::html! {});\n    _ = ::yew::html! { <div>{option_vnode}</div> };\n\n    let opt_string: ::std::option::Option<::std::string::String> =\n        ::std::option::Option::Some(::std::convert::From::from(\"hello\"));\n    _ = ::yew::html! { <div>{opt_string}</div> };\n\n    let opt_attr: ::std::option::Option<::yew::AttrValue> =\n        ::std::option::Option::Some(::yew::AttrValue::Static(\"hello\"));\n    _ = ::yew::html! { <div>{opt_attr}</div> };\n\n    let opt_none: ::std::option::Option<::std::string::String> = ::std::option::Option::None;\n    _ = ::yew::html! { <div>{opt_none}</div> };\n\n    let num = 42i32;\n    _ = ::yew::html! { <div>{&num}</div> };\n\n    let text = ::std::string::String::new();\n    _ = ::yew::html! { <div>{&text}</div> };\n\n    let sr: &::core::primitive::str = \"hello\";\n    _ = ::yew::html! { <div>{&sr}</div> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/html-if-fail.rs",
    "content": "use yew::prelude::*;\n\nfn compile_fail() {\n    html! { if {} };\n    html! { if 42 {} };\n    html! { if true {} else };\n    html! { if true {} else if {} };\n    html! { if true {} else if true {} else };\n    html! { if true {} else if true {} else };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/html-if-fail.stderr",
    "content": "error: missing condition for `if` expression\n --> tests/html_macro/html-if-fail.rs:4:16\n  |\n4 |     html! { if {} };\n  |                ^^\n\nerror: expected block or `if` after `else`\n --> tests/html_macro/html-if-fail.rs:6:24\n  |\n6 |     html! { if true {} else };\n  |                        ^^^^\n\nerror: missing condition for `if` expression\n --> tests/html_macro/html-if-fail.rs:7:32\n  |\n7 |     html! { if true {} else if {} };\n  |                                ^^\n\nerror: expected block or `if` after `else`\n --> tests/html_macro/html-if-fail.rs:8:40\n  |\n8 |     html! { if true {} else if true {} else };\n  |                                        ^^^^\n\nerror: expected block or `if` after `else`\n --> tests/html_macro/html-if-fail.rs:9:40\n  |\n9 |     html! { if true {} else if true {} else };\n  |                                        ^^^^\n\nerror[E0308]: mismatched types\n --> tests/html_macro/html-if-fail.rs:5:16\n  |\n5 |     html! { if 42 {} };\n  |                ^^ expected `bool`, found integer\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/html-if-pass.rs",
    "content": "#![no_implicit_prelude]\n\nfn compile_pass_lit() {\n    _ = ::yew::html! { if true {} };\n    _ = ::yew::html! { if true { <div/> } };\n    _ = ::yew::html! { if true { <div/><div/> } };\n    _ = ::yew::html! { if true { <><div/><div/></> } };\n    _ = ::yew::html! { if true { { ::yew::html! {} } } };\n    _ = ::yew::html! { if true { { { let _x = 42; ::yew::html! {} } } } };\n    _ = ::yew::html! { if true {} else {} };\n    _ = ::yew::html! { if true {} else if true {} };\n    _ = ::yew::html! { if true {} else if true {} else {} };\n    _ = ::yew::html! { if let ::std::option::Option::Some(text) = ::std::option::Option::Some(\"text\") { <span>{ text }</span> } };\n    _ = ::yew::html! { <><div/>if true {}<div/></> };\n    _ = ::yew::html! { <div>if true {}</div> };\n}\n\nfn compile_pass_expr() {\n    let condition = true;\n\n    _ = ::yew::html! { if condition {} };\n    _ = ::yew::html! { if condition { <div/> } };\n    _ = ::yew::html! { if condition { <div/><div/> } };\n    _ = ::yew::html! { if condition { <><div/><div/></> } };\n    _ = ::yew::html! { if condition { { ::yew::html! {} } } };\n    _ = ::yew::html! { if condition { { { let _x = 42; ::yew::html! {} } } } };\n    _ = ::yew::html! { if condition {} else {} };\n    _ = ::yew::html! { if condition {} else if condition {} };\n    _ = ::yew::html! { if condition {} else if condition {} else {} };\n    _ = ::yew::html! { if let ::std::option::Option::Some(text) = ::std::option::Option::Some(\"text\") { <span>{ text }</span> } };\n    _ = ::yew::html! { <><div/>if condition {}<div/></> };\n    _ = ::yew::html! { <div>if condition {}</div> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/html-node-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn compile_pass() {\n    _ = ::yew::html! { \"\" };\n    _ = ::yew::html! { 'a' };\n    _ = ::yew::html! { \"hello\" };\n    _ = ::yew::html! { 42 };\n    _ = ::yew::html! { 1.234 };\n\n    _ = ::yew::html! { <span>{ \"\" }</span> };\n    _ = ::yew::html! { <span>{ 'a' }</span> };\n    _ = ::yew::html! { <span>{ \"hello\" }</span> };\n    _ = ::yew::html! { <span>{ 42 }</span> };\n    _ = ::yew::html! { <span>{ 1.234 }</span> };\n\n    _ = ::yew::html! { ::std::format!(\"Hello\") };\n    _ = ::yew::html! { {<::std::string::String as ::std::convert::From<&::std::primitive::str>>::from(\"Hello\") } };\n\n    let msg = \"Hello\";\n    _ = ::yew::html! { msg };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/iterable-fail.rs",
    "content": "use yew::prelude::*;\n\nfn compile_fail() {\n    html! { for };\n    html! { for () };\n    html! { {for ()} };\n    html! { for Vec::<()>::new().into_iter() };\n\n    let empty = Vec::<()>::new().into_iter();\n    html! { for empty };\n\n    let empty = Vec::<()>::new();\n    html! { {for empty.iter()} };\n\n    html! {\n        <>\n            <div/>\n            { for () }\n        </>\n    };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/iterable-fail.stderr",
    "content": "error: unexpected end of input, expected one of: identifier, `::`, `<`, `_`, literal, `const`, `ref`, `mut`, `&`, parentheses, square brackets, `..`, `const`\n --> tests/html_macro/iterable-fail.rs:4:5\n  |\n4 |     html! { for };\n  |     ^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: unexpected end of input, expected `in`\n --> tests/html_macro/iterable-fail.rs:5:5\n  |\n5 |     html! { for () };\n  |     ^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: expected `in`\n --> tests/html_macro/iterable-fail.rs:7:33\n  |\n7 |     html! { for Vec::<()>::new().into_iter() };\n  |                                 ^\n\nerror: unexpected end of input, expected `in`\n  --> tests/html_macro/iterable-fail.rs:10:5\n   |\n10 |     html! { for empty };\n   |     ^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: `()` is not an iterator\n --> tests/html_macro/iterable-fail.rs:6:18\n  |\n6 |     html! { {for ()} };\n  |                  ^^ `()` is not an iterator\n  |\n  = help: the trait `Iterator` is not implemented for `()`\n  = note: required for `()` to implement `IntoIterator`\n\nerror[E0277]: `()` doesn't implement `std::fmt::Display`\n  --> tests/html_macro/iterable-fail.rs:13:18\n   |\n13 |     html! { {for empty.iter()} };\n   |                  ^^^^^ `()` cannot be formatted with the default formatter\n   |\n   = help: the trait `std::fmt::Display` is not implemented for `()`\n   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead\n   = help: the trait `FromIterator<A>` is implemented for `VNode`\n   = note: required for `&()` to implement `std::fmt::Display`\n   = note: required for `&()` to implement `ToString`\n   = note: required for `VNode` to implement `From<&()>`\n   = note: required for `&()` to implement `Into<VNode>`\n   = note: required for `VNode` to implement `FromIterator<&()>`\nnote: required by a bound in `collect`\n  --> $RUST/core/src/iter/traits/iterator.rs\n\nerror[E0277]: `()` is not an iterator\n  --> tests/html_macro/iterable-fail.rs:18:19\n   |\n18 |             { for () }\n   |                   ^^ `()` is not an iterator\n   |\n   = help: the trait `Iterator` is not implemented for `()`\n   = note: required for `()` to implement `IntoIterator`\nnote: required by a bound in `into_node_iter`\n  --> $WORKSPACE/packages/yew/src/utils/mod.rs\n   |\n   | pub fn into_node_iter<IT, T, R>(it: IT) -> impl Iterator<Item = R>\n   |        -------------- required by a bound in this function\n   | where\n   |     IT: IntoIterator<Item = T>,\n   |         ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `into_node_iter`\n\nerror[E0277]: `()` is not an iterator\n  --> tests/html_macro/iterable-fail.rs:15:5\n   |\n15 | /     html! {\n16 | |         <>\n17 | |             <div/>\n18 | |             { for () }\n19 | |         </>\n20 | |     };\n   | |_____^ `()` is not an iterator\n   |\n   = help: the trait `Iterator` is not implemented for `()`\n   = note: required for `()` to implement `IntoIterator`\nnote: required by a bound in `into_node_iter`\n  --> $WORKSPACE/packages/yew/src/utils/mod.rs\n   |\n   | pub fn into_node_iter<IT, T, R>(it: IT) -> impl Iterator<Item = R>\n   |        -------------- required by a bound in this function\n   | where\n   |     IT: IntoIterator<Item = T>,\n   |         ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `into_node_iter`\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/iterable-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn empty_vec() -> ::std::vec::Vec<::yew::Html> {\n    ::std::vec::Vec::<::yew::Html>::new()\n}\n\nfn empty_iter() -> impl ::std::iter::Iterator<Item = ::yew::Html> {\n    ::std::iter::empty::<::yew::Html>()\n}\n\nfn main() {\n    _ = ::yew::html! { {for empty_iter()} };\n    _ = ::yew::html! { {for { empty_iter() }} };\n\n    let empty = empty_vec();\n    _ = ::yew::html! { {for empty} };\n\n    _ = ::yew::html! {<>\n        {for empty_vec()}\n    </>};\n    _ = ::yew::html! {<>\n        {for ::std::iter::IntoIterator::into_iter(empty_vec())}\n    </>};\n    _ = ::yew::html! {<>\n        {for ::std::iter::Iterator::map(0..3, |num| { ::yew::html! { <span>{ num }</span> } })}\n    </>};\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/list-fail.rs",
    "content": "use yew::prelude::*;\n\nfn compile_fail() {\n    // missing closing tag\n    html! { <> };\n    html! { <><> };\n    html! { <><></> };\n\n    // missing starting tag\n    html! { </> };\n    html! { </></> };\n\n    // multiple root nodes\n    html! { <></><></> };\n    // invalid child content\n    html! { <>invalid</> };\n    // no key value\n    html! { <key=></> };\n    // wrong closing tag\n    html! { <key=\"key\".to_string()></key> };\n\n    // multiple keys\n    html! { <key=\"first key\" key=\"second key\" /> };\n    // invalid prop\n    html! { <some_attr=\"test\"></> };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/list-fail.stderr",
    "content": "error: this opening fragment has no corresponding closing fragment\n --> tests/html_macro/list-fail.rs:5:13\n  |\n5 |     html! { <> };\n  |             ^^\n\nerror: this opening fragment has no corresponding closing fragment\n --> tests/html_macro/list-fail.rs:6:15\n  |\n6 |     html! { <><> };\n  |               ^^\n\nerror: this opening fragment has no corresponding closing fragment\n --> tests/html_macro/list-fail.rs:7:13\n  |\n7 |     html! { <><></> };\n  |             ^^\n\nerror: this closing fragment has no corresponding opening fragment\n  --> tests/html_macro/list-fail.rs:10:13\n   |\n10 |     html! { </> };\n   |             ^^^\n\nerror: this closing fragment has no corresponding opening fragment\n  --> tests/html_macro/list-fail.rs:11:13\n   |\n11 |     html! { </></> };\n   |             ^^^\n\nerror: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n  --> tests/html_macro/list-fail.rs:14:18\n   |\n14 |     html! { <></><></> };\n   |                  ^^^^^\n\nerror: expected a valid html element\n  --> tests/html_macro/list-fail.rs:16:15\n   |\n16 |     html! { <>invalid</> };\n   |               ^^^^^^^\n\nerror: expected an expression following this equals sign\n  --> tests/html_macro/list-fail.rs:18:17\n   |\n18 |     html! { <key=></> };\n   |                 ^\n\nerror: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::MethodCall {\n           attrs: [],\n           receiver: Expr::Lit {\n               attrs: [],\n               lit: Lit::Str {\n                   token: \"key\",\n               },\n           },\n           dot_token: Dot,\n           method: Ident {\n               ident: \"to_string\",\n               span: #0 bytes(404..413),\n           },\n           turbofish: None,\n           paren_token: Paren,\n           args: [],\n       }\n  --> tests/html_macro/list-fail.rs:20:18\n   |\n20 |     html! { <key=\"key\".to_string()></key> };\n   |                  ^^^^^^^^^^^^^^^^^\n\nerror: only a single `key` prop is allowed on a fragment\n  --> tests/html_macro/list-fail.rs:23:30\n   |\n23 |     html! { <key=\"first key\" key=\"second key\" /> };\n   |                              ^^^\n\nerror: fragments only accept the `key` prop\n  --> tests/html_macro/list-fail.rs:25:14\n   |\n25 |     html! { <some_attr=\"test\"></> };\n   |              ^^^^^^^^^\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/list-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn main() {\n    _ = ::yew::html! {};\n    _ = ::yew::html! { <></> };\n    _ = ::yew::html! {\n        <>\n            <></>\n            <></>\n        </>\n    };\n    _ = ::yew::html! {\n        <key={::std::string::ToString::to_string(\"key\")}>\n        </>\n    };\n\n    let children = ::std::vec![\n        ::yew::html! { <span>{ \"Hello\" }</span> },\n        ::yew::html! { <span>{ \"World\" }</span> },\n    ];\n    _ = ::yew::html! { <>{ children }</> };\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/missing-props-diagnostics-fail.rs",
    "content": "use yew::prelude::*;\n\n#[component]\npub fn App() -> Html {\n    html! {\n        <Foo />\n    }\n}\n\n#[component]\npub fn App1() -> Html {\n    html! {\n        <Foo bar={\"bar\".to_string()} />\n    }\n}\n\n#[component]\npub fn App2() -> Html {\n    html! {\n        <Foo bar={\"bar\".to_string()} baz={42} />\n    }\n}\n\n#[derive(Properties, PartialEq, Clone)]\npub struct FooProps {\n    pub bar: String,\n    pub baz: u32,\n}\n\n#[component]\npub fn Foo(_props: &FooProps) -> Html {\n    html! {}\n}\n\nfn main() {}"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/missing-props-diagnostics-fail.stderr",
    "content": "error[E0277]: not all required properties have been provided\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:6:10\n   |\n6  |         <Foo />\n   |          ^^^ missing required properties for this component\n   |\n   = help: the trait `HasProp<bar, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckFooPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<children, HasContextProviderPropschildren<B>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<yew::context::_ContextProviderProps::context, HasContextProviderPropscontext<B>>`\n             `HasFooPropsbar<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `CheckFooPropsAll<AssertAllProps>` to implement `HasAllProps<FooProps, (_, _)>`\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:24:10\n   |\n24 | #[derive(Properties, PartialEq, Clone)]\n   |          ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `AssertAllProps` to implement `AllPropsFor<FooPropsBuilder, (_, _)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: not all required properties have been provided\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:6:10\n   |\n6  |         <Foo />\n   |          ^^^ missing required properties for this component\n   |\n   = help: the trait `HasProp<baz, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckFooPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<children, HasContextProviderPropschildren<B>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<yew::context::_ContextProviderProps::context, HasContextProviderPropscontext<B>>`\n             `HasFooPropsbar<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `CheckFooPropsAll<AssertAllProps>` to implement `HasAllProps<FooProps, (_, _)>`\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:24:10\n   |\n24 | #[derive(Properties, PartialEq, Clone)]\n   |          ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `AssertAllProps` to implement `AllPropsFor<FooPropsBuilder, (_, _)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: property `baz` is required but not provided\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:13:10\n   |\n13 |         <Foo bar={\"bar\".to_string()} />\n   |          ^^^ missing required property `baz`\n   |\n   = help: the trait `HasProp<baz, _>` is not implemented for `AssertAllProps`\n   = help: the following other types implement trait `HasProp<P, How>`:\n             `CheckChildrenPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckContextProviderPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `CheckFooPropsAll<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropschildren<B>` implements `HasProp<children, HasContextProviderPropschildren<B>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n             `HasContextProviderPropscontext<B>` implements `HasProp<yew::context::_ContextProviderProps::context, HasContextProviderPropscontext<B>>`\n             `HasFooPropsbar<B>` implements `HasProp<P, &dyn HasProp<P, How>>`\n           and $N others\nnote: required for `HasFooPropsbar<AssertAllProps>` to implement `HasProp<baz, &dyn HasProp<baz, _>>`\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:24:10\n   |\n24 | #[derive(Properties, PartialEq, Clone)]\n   |          ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\nnote: required for `CheckFooPropsAll<HasFooPropsbar<AssertAllProps>>` to implement `HasAllProps<FooProps, (HasFooPropsbar<AssertAllProps>, &dyn HasProp<baz, _>)>`\n  --> tests/html_macro/missing-props-diagnostics-fail.rs:24:10\n   |\n24 | #[derive(Properties, PartialEq, Clone)]\n   |          ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro\n   = note: required for `HasFooPropsbar<AssertAllProps>` to implement `AllPropsFor<FooPropsBuilder, (HasFooPropsbar<AssertAllProps>, &dyn HasProp<baz, _>)>`\nnote: required by a bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`\n  --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n   |\n   |         pub fn build<How>(self) -> B::Output\n   |                ----- required by a bound in this associated function\n   |         where\n   |             Token: AllPropsFor<B, How>,\n   |                    ^^^^^^^^^^^^^^^^^^^ required by this bound in `PreBuild::<Token, B>::build`\n   = note: this error originates in the macro `html` which comes from the expansion of the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/node-fail.rs",
    "content": "use yew::prelude::*;\n\nfn compile_fail() {\n    html! { \"valid\" \"invalid\" };\n    html! { <span>{ \"valid\" \"invalid\" }</span> };\n    html! { () };\n    html! { invalid };\n\n    // unsupported literals\n    html! {  b'a' };\n    html! {  b\"str\" };\n    html! {  <span>{ b'a' }</span> };\n    html! {  <span>{ b\"str\" }</span> };\n\n    let not_node = || ();\n    html! {\n        not_node()\n    };\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/node-fail.stderr",
    "content": "error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)\n --> tests/html_macro/node-fail.rs:4:21\n  |\n4 |     html! { \"valid\" \"invalid\" };\n  |                     ^^^^^^^^^\n\nerror: unexpected token, expected `}`\n --> tests/html_macro/node-fail.rs:5:29\n  |\n5 |     html! { <span>{ \"valid\" \"invalid\" }</span> };\n  |                             ^^^^^^^^^\n\nerror: byte-strings can't be converted to HTML text\n                                note: remove the `b` prefix or convert this to a `String`\n  --> tests/html_macro/node-fail.rs:11:14\n   |\n11 |     html! {  b\"str\" };\n   |              ^^^^^^\n\nerror: byte-strings can't be converted to HTML text\n                                note: remove the `b` prefix or convert this to a `String`\n  --> tests/html_macro/node-fail.rs:13:22\n   |\n13 |     html! {  <span>{ b\"str\" }</span> };\n   |                      ^^^^^^\n\nerror[E0425]: cannot find value `invalid` in this scope\n --> tests/html_macro/node-fail.rs:7:13\n  |\n7 |     html! { invalid };\n  |             ^^^^^^^ not found in this scope\n\nerror[E0277]: `()` doesn't implement `std::fmt::Display`\n --> tests/html_macro/node-fail.rs:6:13\n  |\n6 |     html! { () };\n  |             ^^ `()` cannot be formatted with the default formatter\n  |\n  = help: the trait `std::fmt::Display` is not implemented for `()`\n  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead\n  = help: the following other types implement trait `From<T>`:\n            `VNode` implements `From<ChildrenRenderer<VNode>>`\n            `VNode` implements `From<T>`\n            `VNode` implements `From<VChild<COMP>>`\n            `VNode` implements `From<yew::virtual_dom::VComp>`\n            `VNode` implements `From<yew::virtual_dom::VList>`\n            `VNode` implements `From<yew::virtual_dom::VPortal>`\n            `VNode` implements `From<yew::virtual_dom::VSuspense>`\n            `VNode` implements `From<yew::virtual_dom::VTag>`\n            `VNode` implements `From<yew::virtual_dom::VText>`\n  = note: required for `()` to implement `ToString`\n  = note: required for `VNode` to implement `From<()>`\n  = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror[E0277]: `()` doesn't implement `std::fmt::Display`\n  --> tests/html_macro/node-fail.rs:17:9\n   |\n17 |         not_node()\n   |         ^^^^^^^^ `()` cannot be formatted with the default formatter\n   |\n   = help: the trait `std::fmt::Display` is not implemented for `()`\n   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead\n   = help: the following other types implement trait `From<T>`:\n             `VNode` implements `From<ChildrenRenderer<VNode>>`\n             `VNode` implements `From<T>`\n             `VNode` implements `From<VChild<COMP>>`\n             `VNode` implements `From<yew::virtual_dom::VComp>`\n             `VNode` implements `From<yew::virtual_dom::VList>`\n             `VNode` implements `From<yew::virtual_dom::VPortal>`\n             `VNode` implements `From<yew::virtual_dom::VSuspense>`\n             `VNode` implements `From<yew::virtual_dom::VTag>`\n             `VNode` implements `From<yew::virtual_dom::VText>`\n   = note: required for `()` to implement `ToString`\n   = note: required for `VNode` to implement `From<()>`\n   = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/node-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn main() {\n    _ = ::yew::html! { b'b' };\n    _ = ::yew::html! { 'a' };\n    _ = ::yew::html! { \"hello\" };\n    _ = ::yew::html! { 42 };\n    _ = ::yew::html! { 1.234 };\n    _ = ::yew::html! { true };\n\n    _ = ::yew::html! { <span>{ \"\" }</span> };\n    _ = ::yew::html! { <span>{ 'a' }</span> };\n    _ = ::yew::html! { <span>{ \"hello\" }</span> };\n    _ = ::yew::html! { <span>{ \"42\" }</span> };\n    _ = ::yew::html! { <span>{ \"1.234\" }</span> };\n    _ = ::yew::html! { <span>{ \"true\" }</span> };\n\n    _ = ::yew::html! { ::std::format!(\"Hello\") };\n    _ = ::yew::html! { ::std::string::ToString::to_string(\"Hello\") };\n\n    let msg = \"Hello\";\n    _ = ::yew::html! { msg };\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro/svg-pass.rs",
    "content": "#![no_implicit_prelude]\n\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\nfn main() {\n    // Ensure Rust keywords can be used as element names.\n    // See: #1771\n    _ = ::yew::html! {\n        <a class=\"btn btn-primary\" href=\"https://example.org/\">\n            <svg class=\"bi\" fill=\"currentColor\">\n                <use href=\"/bootstrap-icons.svg#wrench\"/>\n            </svg>\n            <span>{\"Go to example.org\"}</span>\n        </a>\n    };\n\n    // some general SVG\n    _ = ::yew::html! {\n        <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n            <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n            <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n            <g filter=\"url(#filter0_d)\">\n                <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n                <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n            </g>\n            <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n            <defs>\n                <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                    <feGaussianBlur stdDeviation=\"2\"/>\n                    <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n                </filter>\n            </defs>\n        </svg>\n    };\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/html_macro_test.rs",
    "content": "use yew::{html, html_nested};\n\n#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn html_macro() {\n    let t = trybuild::TestCases::new();\n\n    t.pass(\"tests/html_macro/*-pass.rs\");\n    t.compile_fail(\"tests/html_macro/*-fail.rs\");\n}\n\n#[test]\n#[should_panic(\n    expected = \"a dynamic tag tried to create a `<br>` tag with children. `<br>` is a void \\\n                element which can't have any children.\"\n)]\nfn dynamic_tags_catch_void_elements() {\n    let _ = html! {\n        <@{\"br\"}>\n            <span>{ \"No children allowed\" }</span>\n        </@>\n    };\n}\n\n#[test]\n#[should_panic(expected = \"a dynamic tag returned a tag name containing non ASCII characters: `❤`\")]\nfn dynamic_tags_catch_non_ascii() {\n    let _ = html! {\n        <@{\"❤\"}/>\n    };\n}\n\n/// test that compilation on html elements pass\n/// fixes: https://github.com/yewstack/yew/issues/2268\n#[test]\nfn html_nested_macro_on_html_element() {\n    let _node = html_nested! {\n        <feBlend/>\n    };\n    let _node = html_nested! {\n        <input/>\n    };\n}\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro/props-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties, PartialEq)]\nstruct Props {\n    a: usize,\n}\n\nfn compile_fail() {\n    yew::props!(Props { ref: NodeRef::default(), key: \"key\" });\n    yew::props!(Props { a: 5, fail: 10 });\n\n    let props = yew::props!(Props { a: 1 });\n    yew::props!(Props { a: 1, ..props });\n\n    yew::props!(Props { does_not_exist });\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro/props-fail.stderr",
    "content": "error: special props cannot be specified in the `props!` macro\n --> tests/props_macro/props-fail.rs:9:25\n  |\n9 |     yew::props!(Props { ref: NodeRef::default(), key: \"key\" });\n  |                         ^^^\n\nerror: special props cannot be specified in the `props!` macro\n --> tests/props_macro/props-fail.rs:9:50\n  |\n9 |     yew::props!(Props { ref: NodeRef::default(), key: \"key\" });\n  |                                                  ^^^\n\nerror: expected ident\n  --> tests/props_macro/props-fail.rs:13:31\n   |\n13 |     yew::props!(Props { a: 1, ..props });\n   |                               ^\n\nerror[E0425]: cannot find value `does_not_exist` in this scope\n  --> tests/props_macro/props-fail.rs:15:25\n   |\n15 |     yew::props!(Props { does_not_exist });\n   |                         ^^^^^^^^^^^^^^ not found in this scope\n\nerror[E0609]: no field `fail` on type `Props`\n  --> tests/props_macro/props-fail.rs:10:31\n   |\n10 |     yew::props!(Props { a: 5, fail: 10 });\n   |                               ^^^^ unknown field\n   |\n   = note: available field is: `a`\n\nerror[E0599]: no method named `fail` found for struct `PropsBuilder` in the current scope\n  --> tests/props_macro/props-fail.rs:10:31\n   |\n3  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `fail` not found for this struct\n...\n10 |     yew::props!(Props { a: 5, fail: 10 });\n   |                               ^^^^ method not found in `PropsBuilder`\n\nerror[E0609]: no field `does_not_exist` on type `Props`\n  --> tests/props_macro/props-fail.rs:15:25\n   |\n15 |     yew::props!(Props { does_not_exist });\n   |                         ^^^^^^^^^^^^^^ unknown field\n   |\n   = note: available field is: `a`\n\nerror[E0599]: no method named `does_not_exist` found for struct `PropsBuilder` in the current scope\n  --> tests/props_macro/props-fail.rs:15:25\n   |\n3  | #[derive(Clone, Properties, PartialEq)]\n   |                 ---------- method `does_not_exist` not found for this struct\n...\n15 |     yew::props!(Props { does_not_exist });\n   |                         ^^^^^^^^^^^^^^ method not found in `PropsBuilder`\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro/props-pass.rs",
    "content": "\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\nstruct Props {\n    a: ::std::primitive::usize,\n    #[prop_or_default]\n    b: ::std::primitive::usize,\n}\n\nfn pass_simple_props() {\n    ::yew::props!(Props { a: 5 });\n    let (a, b) = (3, 5);\n    ::yew::props!(Props { a, b });\n}\n\n#[derive(::yew::Properties, ::std::cmp::PartialEq)]\npub struct RawIdentProps {\n    r#true: ::std::primitive::usize,\n    #[prop_or_default]\n    r#pointless_raw_name: ::std::primitive::usize,\n}\n\n#[derive(::yew::Properties)]\npub struct SelfRefProps<'a, T> {\n    x: ::std::boxed::Box<T>,\n    y: ::std::boxed::Box<Self>,\n    z: &'a Self,\n    a: ::std::marker::PhantomData<(&'a Self, Self)>,\n    b: ::std::marker::PhantomData<::std::boxed::Box<Self>>,\n    c: fn(&Self) -> Self,\n}\n\nimpl<T> ::std::cmp::PartialEq for SelfRefProps<'_, T> {\n    fn eq(&self, _: &Self) -> ::std::primitive::bool {\n        ::std::unimplemented!()\n    }\n}\n\nfn pass_raw_idents() {\n    ::yew::props!(RawIdentProps { r#true: 5 });\n    let (r#true, r#pointless_raw_name) = (3, 5);\n    ::yew::props!(RawIdentProps { r#true, r#pointless_raw_name });\n}\n\n#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\nstruct BuildProp {\n    build: ::std::primitive::usize,\n}\n\nfn pass_build_prop() {\n    ::yew::props!(BuildProp { build: 5 });\n}\n\n#[derive(::yew::Properties, ::std::cmp::PartialEq)]\nstruct GenericProps<T: ::std::cmp::PartialEq> {\n    item: T,\n}\n\nfn pass_generic_props<T: ::std::cmp::PartialEq>(the_item: T) {\n    ::yew::props!(GenericProps<T> { item: the_item });\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro/resolve-prop-fail.rs",
    "content": "use yew::prelude::*;\n\n#[derive(Clone, Properties)]\nstruct Props {}\n\nstruct MyComp;\nimpl Component for MyComp {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        unimplemented!()\n    }\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        unimplemented!()\n    }\n}\n\ntrait NotAComponent {\n    type Properties;\n}\n\nstruct MyNotAComponent;\nimpl NotAComponent for MyNotAComponent {\n    type Properties = ();\n}\n\nfn compile_fail() {\n    yew::props!(Vec<_> {});\n    yew::props!(MyComp {});\n    yew::props!(MyNotAComponent::Properties {});\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro/resolve-prop-fail.stderr",
    "content": "error[E0277]: can't compare `Props` with `Props`\n --> tests/props_macro/resolve-prop-fail.rs:4:8\n  |\n4 | struct Props {}\n  |        ^^^^^ no implementation for `Props == Props`\n  |\n  = help: the trait `PartialEq` is not implemented for `Props`\nnote: required by a bound in `yew::Properties`\n --> $WORKSPACE/packages/yew/src/html/component/properties.rs\n  |\n  | pub trait Properties: PartialEq {\n  |                       ^^^^^^^^^ required by this bound in `Properties`\nhelp: consider annotating `Props` with `#[derive(PartialEq)]`\n  |\n4 + #[derive(PartialEq)]\n5 | struct Props {}\n  |\n\nerror[E0277]: can't compare `Props` with `Props`\n --> tests/props_macro/resolve-prop-fail.rs:9:23\n  |\n9 |     type Properties = Props;\n  |                       ^^^^^ no implementation for `Props == Props`\n  |\n  = help: the trait `PartialEq` is not implemented for `Props`\n  = help: the following other types implement trait `yew::Properties`:\n            ()\n            ChildrenProps\n            ContextProviderProps<T>\n            Props\n            SuspenseProps\n  = note: required for `<MyComp as yew::Component>::Properties` to implement `yew::Properties`\nnote: required by a bound in `yew::Component::Properties`\n --> $WORKSPACE/packages/yew/src/html/component/mod.rs\n  |\n  |     type Properties: Properties;\n  |                      ^^^^^^^^^^ required by this bound in `Component::Properties`\nhelp: consider annotating `Props` with `#[derive(PartialEq)]`\n  |\n4   + #[derive(PartialEq)]\n5   | struct Props {}\n    |\n\nerror[E0277]: the trait bound `Vec<_>: yew::Properties` is not satisfied\n  --> tests/props_macro/resolve-prop-fail.rs:29:17\n   |\n29 |     yew::props!(Vec<_> {});\n   |                 ^^^^^^ the trait `yew::Properties` is not implemented for `Vec<_>`\n   |\n   = help: the following other types implement trait `yew::Properties`:\n             ()\n             ChildrenProps\n             ContextProviderProps<T>\n             Props\n             SuspenseProps\n\nerror[E0277]: the trait bound `Vec<_>: yew::Properties` is not satisfied\n  --> tests/props_macro/resolve-prop-fail.rs:29:17\n   |\n29 |     yew::props!(Vec<_> {});\n   |                 ^^^ the trait `yew::Properties` is not implemented for `Vec<_>`\n   |\n   = help: the following other types implement trait `yew::Properties`:\n             ()\n             ChildrenProps\n             ContextProviderProps<T>\n             Props\n             SuspenseProps\n\nerror[E0277]: the trait bound `MyComp: yew::Properties` is not satisfied\n  --> tests/props_macro/resolve-prop-fail.rs:30:17\n   |\n30 |     yew::props!(MyComp {});\n   |                 ^^^^^^ the trait `yew::Properties` is not implemented for `MyComp`\n   |\n   = help: the following other types implement trait `yew::Properties`:\n             ()\n             ChildrenProps\n             ContextProviderProps<T>\n             Props\n             SuspenseProps\n\nerror[E0277]: the trait bound `MyNotAComponent: yew::Component` is not satisfied\n  --> tests/props_macro/resolve-prop-fail.rs:31:17\n   |\n31 |     yew::props!(MyNotAComponent::Properties {});\n   |                 ^^^^^^^^^^^^^^^ the trait `yew::Component` is not implemented for `MyNotAComponent`\n   |\n   = help: the following other types implement trait `yew::Component`:\n             ContextProvider<T>\n             MyComp\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro/resolve-prop-pass.rs",
    "content": "\n// Shadow primitives\n#[allow(non_camel_case_types)]\npub struct bool;\n#[allow(non_camel_case_types)]\npub struct char;\n#[allow(non_camel_case_types)]\npub struct f32;\n#[allow(non_camel_case_types)]\npub struct f64;\n#[allow(non_camel_case_types)]\npub struct i128;\n#[allow(non_camel_case_types)]\npub struct i16;\n#[allow(non_camel_case_types)]\npub struct i32;\n#[allow(non_camel_case_types)]\npub struct i64;\n#[allow(non_camel_case_types)]\npub struct i8;\n#[allow(non_camel_case_types)]\npub struct isize;\n#[allow(non_camel_case_types)]\npub struct str;\n#[allow(non_camel_case_types)]\npub struct u128;\n#[allow(non_camel_case_types)]\npub struct u16;\n#[allow(non_camel_case_types)]\npub struct u32;\n#[allow(non_camel_case_types)]\npub struct u64;\n#[allow(non_camel_case_types)]\npub struct u8;\n#[allow(non_camel_case_types)]\npub struct usize;\n\n#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]\nstruct Props {\n    n: ::std::primitive::i32,\n}\n\nstruct MyComp;\nimpl ::yew::Component for MyComp {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &::yew::Context<Self>) -> Self {\n        ::std::unimplemented!()\n    }\n    fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {\n        ::std::unimplemented!()\n    }\n}\n\nfn compile_pass() {\n    ::yew::props!(Props { n: 1 });\n    ::yew::props!(self::Props { n: 1 });\n    ::yew::props!(MyComp::Properties { n: 2 });\n    ::yew::props!(self::MyComp::Properties { n: 3 });\n    ::yew::props!(<MyComp as ::yew::Component>::Properties { n: 5});\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-macro/tests/props_macro_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn props_macro() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/props_macro/*-pass.rs\");\n    t.compile_fail(\"tests/props_macro/*-fail.rs\");\n}\n\n#[test]\nfn props_order() {\n    #[derive(yew::Properties, PartialEq)]\n    struct Props {\n        first: usize,\n        second: usize,\n        last: usize,\n    }\n\n    let mut g = 1..=3;\n    let props = yew::props!(Props {\n        first: g.next().unwrap(),\n        second: g.next().unwrap(),\n        last: g.next().unwrap()\n    });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n"
  },
  {
    "path": "packages/yew-router/Cargo.toml",
    "content": "[package]\nname = \"yew-router\"\nversion = \"0.20.0\"\nauthors = [\"Hamza <muhammadhamza1311@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\nreadme = \"README.md\"\nkeywords = [\"web\", \"yew\", \"router\"]\ncategories = [\"gui\", \"web-programming\"]\ndescription = \"A router implementation for the Yew framework\"\nrepository = \"https://github.com/yewstack/yew\"\nrust-version = \"1.84.0\"\n\n[dependencies]\nyew = { version = \"0.23.0\", path = \"../yew\", default-features= false }\nyew-router-macro = { version = \"0.20.0\", path = \"../yew-router-macro\" }\n\nwasm-bindgen.workspace = true\njs-sys.workspace = true\ngloo = { workspace = true, features = [\"futures\"] }\nroute-recognizer = \"0.3\"\nserde.workspace = true\nserde_urlencoded = \"0.7.1\"\ntracing = \"0.1.44\"\nurlencoding = \"2.1.3\"\n\n[dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"Document\",\n    \"HtmlBaseElement\",\n    \"Window\",\n]\n\n[dev-dependencies]\nwasm-bindgen-test = \"0.3\"\nserde = { workspace = true, features = [\"derive\"] }\nyew = { version = \"0.23.0\", path = \"../yew\", features = [\"csr\"] }\n\n[dev-dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"HtmlHeadElement\",\n]\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "packages/yew-router/Makefile.toml",
    "content": "[tasks.test]\ncommand = \"wasm-pack\"\nargs = [\n    \"test\",\n    \"--firefox\",\n    \"--headless\",\n]\n"
  },
  {
    "path": "packages/yew-router/README.md",
    "content": "# yew-router\nA routing library for the [Yew](https://github.com/yewstack/yew) frontend framework.\n\n[Read on how to use it on yew.rs](https://yew.rs/docs/concepts/router)"
  },
  {
    "path": "packages/yew-router/src/components/link.rs",
    "content": "use serde::Serialize;\nuse wasm_bindgen::UnwrapThrowExt;\nuse yew::prelude::*;\nuse yew::virtual_dom::AttrValue;\n\nuse crate::navigator::NavigatorKind;\nuse crate::prelude::*;\nuse crate::{utils, Routable};\n\n/// Props for [`Link`]\n#[derive(Properties, Clone, PartialEq)]\npub struct LinkProps<R, Q = (), S = ()>\nwhere\n    R: Routable,\n    Q: Clone + PartialEq + Serialize,\n    S: Clone + PartialEq,\n{\n    /// CSS classes to add to the anchor element (optional).\n    #[prop_or_default]\n    pub classes: Classes,\n    /// Route that will be pushed when the anchor is clicked.\n    pub to: R,\n    /// Route query data\n    #[prop_or_default]\n    pub query: Option<Q>,\n    /// Route state data\n    #[prop_or_default]\n    pub state: Option<S>,\n    #[prop_or_default]\n    pub disabled: bool,\n    /// [`NodeRef`](yew::html::NodeRef) for the `<a>` element.\n    #[prop_or_default]\n    pub anchor_ref: NodeRef,\n    #[prop_or_default]\n    pub children: Html,\n}\n\n/// A wrapper around `<a>` tag to be used with [`Router`](crate::Router)\n#[component]\npub fn Link<R, Q = (), S = ()>(props: &LinkProps<R, Q, S>) -> Html\nwhere\n    R: Routable + 'static,\n    Q: Clone + PartialEq + Serialize + 'static,\n    S: Clone + PartialEq + 'static,\n{\n    let LinkProps {\n        classes,\n        to,\n        query,\n        state,\n        disabled,\n        anchor_ref,\n        children,\n    } = props.clone();\n\n    let navigator = use_navigator().expect_throw(\"failed to get navigator\");\n\n    let onclick = {\n        let navigator = navigator.clone();\n        let to = to.clone();\n        let query = query.clone();\n        let state = state.clone();\n\n        Callback::from(move |e: MouseEvent| {\n            if e.meta_key() || e.ctrl_key() || e.shift_key() || e.alt_key() {\n                return;\n            }\n            e.prevent_default();\n            match (&state, &query) {\n                (None, None) => {\n                    navigator.push(&to);\n                }\n                (Some(state), None) => {\n                    navigator.push_with_state(&to, state.clone());\n                }\n                (None, Some(query)) => {\n                    navigator\n                        .push_with_query(&to, query)\n                        .expect_throw(\"failed push history with query\");\n                }\n                (Some(state), Some(query)) => {\n                    navigator\n                        .push_with_query_and_state(&to, query, state.clone())\n                        .expect_throw(\"failed push history with query and state\");\n                }\n            }\n        })\n    };\n\n    let href = {\n        let route_s = to.to_path();\n        let pathname = navigator.prefix_basename(&route_s);\n        let mut path = query\n            .and_then(|query| serde_urlencoded::to_string(query).ok())\n            .and_then(|query| utils::compose_path(&pathname, &query))\n            .unwrap_or_else(|| pathname.into_owned());\n\n        if navigator.kind() == NavigatorKind::Hash {\n            path.insert(0, '#');\n        }\n\n        AttrValue::from(path)\n    };\n\n    html! {\n        <a class={classes}\n            {href}\n            {onclick}\n            {disabled}\n            ref={anchor_ref}\n        >\n            { children }\n        </a>\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/components/mod.rs",
    "content": "//! Components to interface with [Router][crate::Router].\n\nmod link;\nmod redirect;\npub use link::*;\npub use redirect::*;\n"
  },
  {
    "path": "packages/yew-router/src/components/redirect.rs",
    "content": "use wasm_bindgen::UnwrapThrowExt;\nuse yew::prelude::*;\n\nuse crate::hooks::use_navigator;\nuse crate::Routable;\n\n/// Props for [`Redirect`]\n#[derive(Properties, Clone, PartialEq, Eq)]\npub struct RedirectProps<R: Routable> {\n    /// Route that will be pushed when the component is rendered.\n    pub to: R,\n}\n\n/// A component that will redirect to specified route when rendered.\n#[component(Redirect)]\npub fn redirect<R>(props: &RedirectProps<R>) -> Html\nwhere\n    R: Routable + 'static,\n{\n    let history = use_navigator().expect_throw(\"failed to read history.\");\n\n    let target_route = props.to.clone();\n    use_effect(move || {\n        history.push(&target_route);\n\n        || {}\n    });\n\n    Html::default()\n}\n"
  },
  {
    "path": "packages/yew-router/src/hooks.rs",
    "content": "//! Hooks to access router state and navigate between pages.\n\nuse yew::prelude::*;\n\nuse crate::history::*;\nuse crate::navigator::Navigator;\nuse crate::routable::Routable;\nuse crate::router::{LocationContext, NavigatorContext};\n\n/// A hook to access the [`Navigator`].\n#[hook]\npub fn use_navigator() -> Option<Navigator> {\n    use_context::<NavigatorContext>().map(|m| m.navigator())\n}\n\n/// A hook to access the current [`Location`].\n#[hook]\npub fn use_location() -> Option<Location> {\n    Some(use_context::<LocationContext>()?.location())\n}\n\n/// A hook to access the current route.\n///\n/// This hook will return [`None`] if there's no available location or none of the routes match.\n///\n/// # Note\n///\n/// If your `Routable` has a `#[not_found]` route, you can use `.unwrap_or_default()` instead of\n/// `.unwrap()` to unwrap.\n#[hook]\npub fn use_route<R>() -> Option<R>\nwhere\n    R: Routable + 'static,\n{\n    let navigator = use_navigator()?;\n    let location = use_location()?;\n    let path = navigator.strip_basename(location.path().into());\n\n    R::recognize(&path)\n}\n"
  },
  {
    "path": "packages/yew-router/src/lib.rs",
    "content": "//! Provides routing faculties using the browser history API to build\n//! Single Page Applications (SPAs) using [Yew web framework](https://yew.rs).\n//!\n//! # Usage\n//!\n//! ```rust\n//! use yew::functional::*;\n//! use yew::prelude::*;\n//! use yew_router::prelude::*;\n//!\n//! #[derive(Debug, Clone, Copy, PartialEq, Routable)]\n//! enum Route {\n//!     #[at(\"/\")]\n//!     Home,\n//!     #[at(\"/secure\")]\n//!     Secure,\n//!     #[not_found]\n//!     #[at(\"/404\")]\n//!     NotFound,\n//! }\n//!\n//! #[component(Secure)]\n//! fn secure() -> Html {\n//!     let navigator = use_navigator().unwrap();\n//!\n//!     let onclick_callback = Callback::from(move |_| navigator.push(&Route::Home));\n//!     html! {\n//!         <div>\n//!             <h1>{ \"Secure\" }</h1>\n//!             <button onclick={onclick_callback}>{ \"Go Home\" }</button>\n//!         </div>\n//!     }\n//! }\n//!\n//! #[component(Main)]\n//! fn app() -> Html {\n//!     html! {\n//!         <BrowserRouter>\n//!             <Switch<Route> render={switch} />\n//!         </BrowserRouter>\n//!     }\n//! }\n//!\n//! fn switch(routes: Route) -> Html {\n//!     match routes {\n//!         Route::Home => html! { <h1>{ \"Home\" }</h1> },\n//!         Route::Secure => html! {\n//!             <Secure />\n//!         },\n//!         Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n//!     }\n//! }\n//! ```\n//!\n//! # Internals\n//!\n//! The router registers itself as a context provider and makes location information and navigator\n//! available via [`hooks`] or [`RouterScopeExt`](scope_ext::RouterScopeExt).\n//!\n//! # State\n//!\n//! The [`Location`](gloo::history::Location) API has a way to access / store state associated with\n//! session history. Please consult [`location.state()`](crate::history::Location::state) for\n//! detailed usage.\n\nextern crate self as yew_router;\n\n#[doc(hidden)]\n#[path = \"macro_helpers.rs\"]\npub mod __macro;\npub mod components;\npub mod hooks;\npub mod navigator;\nmod routable;\npub mod router;\npub mod scope_ext;\npub mod switch;\npub mod utils;\n\npub use routable::{AnyRoute, Routable};\npub use router::{BrowserRouter, HashRouter, Router};\npub use switch::Switch;\n\npub mod history {\n    //! A module that provides universal session history and location information.\n\n    pub use gloo::history::{\n        AnyHistory, BrowserHistory, HashHistory, History, HistoryError, HistoryResult, Location,\n        MemoryHistory,\n    };\n}\n\npub mod query {\n    //! A module that provides custom query serialization & deserialization.\n\n    pub use gloo::history::query::{FromQuery, Raw, ToQuery};\n}\n\npub mod prelude {\n    //! Prelude module to be imported when working with `yew-router`.\n    //!\n    //! This module re-exports the frequently used types from the crate.\n\n    pub use crate::components::{Link, Redirect};\n    pub use crate::history::Location;\n    pub use crate::hooks::*;\n    pub use crate::navigator::{NavigationError, NavigationResult, Navigator};\n    pub use crate::scope_ext::{LocationHandle, NavigatorHandle, RouterScopeExt};\n    #[doc(no_inline)]\n    pub use crate::Routable;\n    pub use crate::{BrowserRouter, HashRouter, Router, Switch};\n}\n"
  },
  {
    "path": "packages/yew-router/src/macro_helpers.rs",
    "content": "pub use urlencoding::{decode as decode_for_url, encode as encode_for_url};\n\npub fn encode_path_for_url(path: &str) -> String {\n    path.split('/')\n        .map(encode_for_url)\n        .collect::<Vec<_>>()\n        .join(\"/\")\n}\n\nuse crate::utils::strip_slash_suffix;\nuse crate::Routable;\n\n// re-export Router because the macro needs to access it\npub type Router = route_recognizer::Router<String>;\n\n/// Build a `route_recognizer::Router` from a `Routable` type.\npub fn build_router<R: Routable>() -> Router {\n    let mut router = Router::new();\n    R::routes().iter().for_each(|path| {\n        let stripped_route = strip_slash_suffix(path);\n        router.add(stripped_route, path.to_string());\n    });\n\n    router\n}\n\n/// Use a `route_recognizer::Router` to build the route of a `Routable`\npub fn recognize_with_router<R: Routable>(router: &Router, pathname: &str) -> Option<R> {\n    let pathname = strip_slash_suffix(pathname);\n    let matched = router.recognize(pathname);\n\n    match matched {\n        Ok(matched) => R::from_path(matched.handler(), &matched.params().into_iter().collect())\n            .or_else(R::not_found_route),\n        Err(_) => R::not_found_route(),\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/navigator.rs",
    "content": "use std::borrow::Cow;\n\nuse crate::history::{AnyHistory, History, HistoryError, HistoryResult};\nuse crate::query::ToQuery;\nuse crate::routable::Routable;\n\npub type NavigationError = HistoryError;\npub type NavigationResult<T> = HistoryResult<T>;\n\n/// The kind of Navigator Provider.\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum NavigatorKind {\n    /// Browser History.\n    Browser,\n    /// Hash History.\n    Hash,\n    /// Memory History.\n    Memory,\n}\n\n/// A struct to navigate between locations.\n#[derive(Debug, PartialEq, Clone)]\npub struct Navigator {\n    inner: AnyHistory,\n    basename: Option<String>,\n}\n\nimpl Navigator {\n    pub(crate) fn new(history: AnyHistory, basename: Option<String>) -> Self {\n        Self {\n            inner: history,\n            basename,\n        }\n    }\n\n    /// Returns basename of current navigator.\n    pub fn basename(&self) -> Option<&str> {\n        self.basename.as_deref()\n    }\n\n    /// Navigate back 1 page.\n    pub fn back(&self) {\n        self.go(-1);\n    }\n\n    /// Navigate forward 1 page.\n    pub fn forward(&self) {\n        self.go(1);\n    }\n\n    /// Navigate to a specific page with a `delta` relative to current page.\n    ///\n    /// See: <https://developer.mozilla.org/en-US/docs/Web/API/History/go>\n    pub fn go(&self, delta: isize) {\n        self.inner.go(delta);\n    }\n\n    /// Pushes a [`Routable`] entry.\n    pub fn push<R>(&self, route: &R)\n    where\n        R: Routable,\n    {\n        self.inner.push(self.prefix_basename(&route.to_path()));\n    }\n\n    /// Replaces the current history entry with provided [`Routable`] and [`None`] state.\n    pub fn replace<R>(&self, route: &R)\n    where\n        R: Routable,\n    {\n        self.inner.replace(self.prefix_basename(&route.to_path()));\n    }\n\n    /// Pushes a [`Routable`] entry with state.\n    pub fn push_with_state<R, T>(&self, route: &R, state: T)\n    where\n        R: Routable,\n        T: 'static,\n    {\n        self.inner\n            .push_with_state(self.prefix_basename(&route.to_path()), state);\n    }\n\n    /// Replaces the current history entry with provided [`Routable`] and state.\n    pub fn replace_with_state<R, T>(&self, route: &R, state: T)\n    where\n        R: Routable,\n        T: 'static,\n    {\n        self.inner\n            .replace_with_state(self.prefix_basename(&route.to_path()), state);\n    }\n\n    /// Same as `.push()` but affix the queries to the end of the route.\n    pub fn push_with_query<R, Q>(&self, route: &R, query: Q) -> Result<(), Q::Error>\n    where\n        R: Routable,\n        Q: ToQuery,\n    {\n        self.inner\n            .push_with_query(self.prefix_basename(&route.to_path()), query)\n    }\n\n    /// Same as `.replace()` but affix the queries to the end of the route.\n    pub fn replace_with_query<R, Q>(&self, route: &R, query: Q) -> Result<(), Q::Error>\n    where\n        R: Routable,\n        Q: ToQuery,\n    {\n        self.inner\n            .replace_with_query(self.prefix_basename(&route.to_path()), query)\n    }\n\n    /// Same as `.push_with_state()` but affix the queries to the end of the route.\n    pub fn push_with_query_and_state<R, Q, T>(\n        &self,\n        route: &R,\n        query: Q,\n        state: T,\n    ) -> Result<(), Q::Error>\n    where\n        R: Routable,\n        Q: ToQuery,\n        T: 'static,\n    {\n        self.inner\n            .push_with_query_and_state(self.prefix_basename(&route.to_path()), query, state)\n    }\n\n    /// Same as `.replace_with_state()` but affix the queries to the end of the route.\n    pub fn replace_with_query_and_state<R, Q, T>(\n        &self,\n        route: &R,\n        query: Q,\n        state: T,\n    ) -> Result<(), Q::Error>\n    where\n        R: Routable,\n        Q: ToQuery,\n        T: 'static,\n    {\n        self.inner.replace_with_query_and_state(\n            self.prefix_basename(&route.to_path()),\n            query,\n            state,\n        )\n    }\n\n    /// Returns the Navigator kind.\n    pub fn kind(&self) -> NavigatorKind {\n        match &self.inner {\n            AnyHistory::Browser(_) => NavigatorKind::Browser,\n            AnyHistory::Hash(_) => NavigatorKind::Hash,\n            AnyHistory::Memory(_) => NavigatorKind::Memory,\n        }\n    }\n\n    pub(crate) fn prefix_basename<'a>(&self, route_s: &'a str) -> Cow<'a, str> {\n        match self.basename() {\n            Some(base) => {\n                if base.is_empty() && route_s.is_empty() {\n                    Cow::from(\"/\")\n                } else {\n                    Cow::from(format!(\"{base}{route_s}\"))\n                }\n            }\n            None => route_s.into(),\n        }\n    }\n\n    pub(crate) fn strip_basename<'a>(&self, path: Cow<'a, str>) -> Cow<'a, str> {\n        match self.basename() {\n            Some(m) => {\n                let mut path = path\n                    .strip_prefix(m)\n                    .map(|m| Cow::from(m.to_owned()))\n                    .unwrap_or(path);\n\n                if !path.starts_with('/') {\n                    path = format!(\"/{path}\").into();\n                }\n\n                path\n            }\n            None => path,\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/routable.rs",
    "content": "use std::collections::HashMap;\n\npub use yew_router_macro::Routable;\n\n/// Marks an `enum` as routable.\n///\n/// # Implementation\n///\n/// Use derive macro to implement it. Although it *is* possible to implement it manually,\n/// it is discouraged.\n///\n/// # Usage\n///\n/// The functions exposed by this trait are **not** supposed to be consumed directly. Instead use\n/// the functions exposed at the [crate's root][crate] to perform operations with the router.\npub trait Routable: Clone + PartialEq {\n    /// Converts path to an instance of the routes enum.\n    fn from_path(path: &str, params: &HashMap<&str, &str>) -> Option<Self>;\n\n    /// Converts the route to a string that can passed to the history API.\n    fn to_path(&self) -> String;\n\n    /// Lists all the available routes\n    fn routes() -> Vec<&'static str>;\n\n    /// The route to redirect to on 404\n    fn not_found_route() -> Option<Self>;\n\n    /// Match a route based on the path\n    fn recognize(pathname: &str) -> Option<Self>;\n}\n\n/// A special route that accepts any route.\n///\n/// This can be used with [`History`](gloo::history::History) and\n/// [`Location`](gloo::history::Location) when the type of [`Routable`] is unknown.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct AnyRoute {\n    path: String,\n}\n\nimpl Routable for AnyRoute {\n    fn from_path(path: &str, params: &HashMap<&str, &str>) -> Option<Self> {\n        // No params allowed.\n        if params.is_empty() {\n            Some(Self {\n                path: path.to_string(),\n            })\n        } else {\n            None\n        }\n    }\n\n    fn to_path(&self) -> String {\n        self.path.to_string()\n    }\n\n    fn routes() -> Vec<&'static str> {\n        vec![\"/*path\"]\n    }\n\n    fn not_found_route() -> Option<Self> {\n        Some(Self {\n            path: \"/404\".to_string(),\n        })\n    }\n\n    fn recognize(pathname: &str) -> Option<Self> {\n        Some(Self {\n            path: pathname.to_string(),\n        })\n    }\n}\n\nimpl AnyRoute {\n    pub fn new<S: Into<String>>(pathname: S) -> Self {\n        Self {\n            path: pathname.into(),\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/router.rs",
    "content": "//! Router Component.\nuse std::borrow::Cow;\nuse std::rc::Rc;\n\nuse gloo::history::query::Raw;\nuse yew::prelude::*;\nuse yew::virtual_dom::AttrValue;\n\nuse crate::history::{AnyHistory, BrowserHistory, HashHistory, History, Location};\nuse crate::navigator::Navigator;\nuse crate::utils::{base_url, strip_slash_suffix};\n\n/// Props for [`Router`].\n#[derive(Properties, PartialEq, Clone)]\npub struct RouterProps {\n    #[prop_or_default]\n    pub children: Html,\n    pub history: AnyHistory,\n    #[prop_or_default]\n    pub basename: Option<AttrValue>,\n}\n\n#[derive(Clone)]\npub(crate) struct LocationContext {\n    location: Location,\n    // Counter to force update.\n    ctr: u32,\n}\n\nimpl LocationContext {\n    pub fn location(&self) -> Location {\n        self.location.clone()\n    }\n}\n\nimpl PartialEq for LocationContext {\n    fn eq(&self, rhs: &Self) -> bool {\n        self.ctr == rhs.ctr\n    }\n}\n\nimpl Reducible for LocationContext {\n    type Action = Location;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        Self {\n            location: action,\n            ctr: self.ctr + 1,\n        }\n        .into()\n    }\n}\n\n#[derive(Clone, PartialEq)]\npub(crate) struct NavigatorContext {\n    navigator: Navigator,\n}\n\nimpl NavigatorContext {\n    pub fn navigator(&self) -> Navigator {\n        self.navigator.clone()\n    }\n}\n\n/// The base router.\n///\n/// The implementation is separated to make sure <Router /> has the same virtual dom layout as\n/// the <BrowserRouter /> and <HashRouter />.\n#[component(BaseRouter)]\nfn base_router(props: &RouterProps) -> Html {\n    let RouterProps {\n        history,\n        children,\n        basename,\n    } = props.clone();\n\n    let basename = basename.map(|m| strip_slash_suffix(&m).to_owned());\n    let navigator = Navigator::new(history.clone(), basename.clone());\n\n    let old_basename = use_mut_ref(|| Option::<String>::None);\n    let mut old_basename = old_basename.borrow_mut();\n    if basename != *old_basename {\n        // If `old_basename` is `Some`, path is probably prefixed with `old_basename`.\n        // If `old_basename` is `None`, path may or may not be prefixed with the new `basename`,\n        // depending on whether this is the first render.\n        let old_navigator = Navigator::new(\n            history.clone(),\n            old_basename.as_ref().or(basename.as_ref()).cloned(),\n        );\n        old_basename.clone_from(&basename);\n        let location = history.location();\n        let stripped = old_navigator.strip_basename(Cow::from(location.path()));\n        let prefixed = navigator.prefix_basename(&stripped);\n\n        if prefixed != location.path() {\n            history\n                .replace_with_query(prefixed, Raw(location.query_str()))\n                .unwrap_or_else(|never| match never {});\n        } else {\n            // Reaching here is possible if the page loads with the correct path, including the\n            // initial basename. In that case, the new basename would be stripped and then\n            // prefixed right back. While replacing the history would probably be harmless,\n            // we might as well avoid doing it.\n        }\n    }\n\n    let navi_ctx = NavigatorContext { navigator };\n\n    let loc_ctx = use_reducer(|| LocationContext {\n        location: history.location(),\n        ctr: 0,\n    });\n\n    {\n        let loc_ctx_dispatcher = loc_ctx.dispatcher();\n\n        use_effect_with(history, move |history| {\n            let history = history.clone();\n            // Force location update when history changes.\n            loc_ctx_dispatcher.dispatch(history.location());\n\n            let history_cb = {\n                let history = history.clone();\n                move || loc_ctx_dispatcher.dispatch(history.location())\n            };\n\n            let listener = history.listen(history_cb);\n\n            // We hold the listener in the destructor.\n            move || {\n                std::mem::drop(listener);\n            }\n        });\n    }\n\n    html! {\n        <ContextProvider<NavigatorContext> context={navi_ctx}>\n            <ContextProvider<LocationContext> context={(*loc_ctx).clone()}>\n                {children}\n            </ContextProvider<LocationContext>>\n        </ContextProvider<NavigatorContext>>\n    }\n}\n\n/// The Router component.\n///\n/// This provides location and navigator context to its children and switches.\n///\n/// If you are building a web application, you may want to consider using [`BrowserRouter`] instead.\n///\n/// You only need one `<Router />` for each application.\n#[component(Router)]\npub fn router(props: &RouterProps) -> Html {\n    html! {\n        <BaseRouter ..{props.clone()} />\n    }\n}\n\n/// Props for [`BrowserRouter`] and [`HashRouter`].\n#[derive(Properties, PartialEq, Clone)]\npub struct ConcreteRouterProps {\n    pub children: Html,\n    #[prop_or_default]\n    pub basename: Option<AttrValue>,\n}\n\n/// A [`Router`] that provides location information and navigator via [`BrowserHistory`].\n///\n/// This Router uses browser's native history to manipulate session history\n/// and uses regular URL as route.\n///\n/// # Note\n///\n/// The router will by default use the value declared in `<base href=\"...\" />` as its basename.\n/// You may also specify a different basename with props.\n#[component(BrowserRouter)]\npub fn browser_router(props: &ConcreteRouterProps) -> Html {\n    let ConcreteRouterProps { children, basename } = props.clone();\n    let history = use_state(|| AnyHistory::from(BrowserHistory::new()));\n\n    // We acknowledge based in `<base href=\"...\" />`\n    let basename = basename.map(|m| m.to_string()).or_else(base_url);\n\n    html! {\n        <BaseRouter history={(*history).clone()} {basename}>\n            {children}\n        </BaseRouter>\n    }\n}\n\n/// A [`Router`] that provides location information and navigator via [`HashHistory`].\n///\n/// This Router uses browser's native history to manipulate session history\n/// and stores route in hash fragment.\n///\n/// # Warning\n///\n/// Prefer [`BrowserRouter`] whenever possible and use this as a last resort.\n#[component(HashRouter)]\npub fn hash_router(props: &ConcreteRouterProps) -> Html {\n    let ConcreteRouterProps { children, basename } = props.clone();\n    let history = use_state(|| AnyHistory::from(HashHistory::new()));\n\n    html! {\n        <BaseRouter history={(*history).clone()} {basename}>\n            {children}\n        </BaseRouter>\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/scope_ext.rs",
    "content": "use yew::context::ContextHandle;\nuse yew::prelude::*;\n\nuse crate::history::Location;\nuse crate::navigator::Navigator;\nuse crate::routable::Routable;\nuse crate::router::{LocationContext, NavigatorContext};\n\n/// A [`ContextHandle`] for [`add_location_listener`](RouterScopeExt::add_location_listener).\npub struct LocationHandle {\n    _inner: ContextHandle<LocationContext>,\n}\n\n/// A [`ContextHandle`] for [`add_navigator_listener`](RouterScopeExt::add_navigator_listener).\npub struct NavigatorHandle {\n    _inner: ContextHandle<NavigatorContext>,\n}\n\n/// An extension to [`Scope`](yew::html::Scope) that provides location information and navigator\n/// access.\n///\n/// You can access them on `ctx.link()`\n///\n/// # Example\n///\n/// Below is an example of the implementation of the [`Link`](crate::components::Link) component.\n///\n/// ```\n/// # use std::marker::PhantomData;\n/// # use wasm_bindgen::UnwrapThrowExt;\n/// # use yew::prelude::*;\n/// # use yew_router::prelude::*;\n/// # use yew_router::components::LinkProps;\n/// #\n/// # pub struct Link<R: Routable + 'static> {\n/// #     _data: PhantomData<R>,\n/// # }\n/// #\n/// # pub enum Msg {\n/// #     OnClick,\n/// # }\n/// #\n/// impl<R: Routable + 'static> Component for Link<R> {\n///     type Message = Msg;\n///     type Properties = LinkProps<R>;\n///\n///     fn create(_ctx: &Context<Self>) -> Self {\n///         Self { _data: PhantomData }\n///     }\n///\n///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {\n///         match msg {\n///             Msg::OnClick => {\n///                 ctx.link()\n///                     .navigator()\n///                     .expect_throw(\"failed to get navigator.\")\n///                     .push(&ctx.props().to);\n///                 false\n///             }\n///         }\n///     }\n///\n///     fn view(&self, ctx: &Context<Self>) -> Html {\n///         html! {\n///             <a class={ctx.props().classes.clone()}\n///                 href={ctx.props().to.to_path()}\n///                 onclick={ctx.link().callback(|e: MouseEvent| {\n///                     e.prevent_default();\n///                     Msg::OnClick\n///                 })}\n///             >\n///                 { ctx.props().children.clone() }\n///             </a>\n///         }\n///     }\n/// }\n/// ```\npub trait RouterScopeExt {\n    /// Returns current [`Navigator`].\n    fn navigator(&self) -> Option<Navigator>;\n\n    /// Returns current [`Location`].\n    fn location(&self) -> Option<Location>;\n\n    /// Returns current route.\n    fn route<R>(&self) -> Option<R>\n    where\n        R: Routable + 'static;\n\n    /// Adds a listener that gets notified when location changes.\n    ///\n    /// # Note\n    ///\n    /// [`LocationHandle`] works like a normal [`ContextHandle`] and it unregisters the callback\n    /// when the handle is dropped. You need to keep the handle for as long as you need the\n    /// callback.\n    fn add_location_listener(&self, cb: Callback<Location>) -> Option<LocationHandle>;\n\n    /// Adds a listener that gets notified when navigator changes.\n    ///\n    /// # Note\n    ///\n    /// [`NavigatorHandle`] works like a normal [`ContextHandle`] and it unregisters the callback\n    /// when the handle is dropped. You need to keep the handle for as long as you need the\n    /// callback.\n    fn add_navigator_listener(&self, cb: Callback<Navigator>) -> Option<NavigatorHandle>;\n}\n\nimpl<COMP: Component> RouterScopeExt for yew::html::Scope<COMP> {\n    fn navigator(&self) -> Option<Navigator> {\n        self.context::<NavigatorContext>(Callback::from(|_| {}))\n            .map(|(m, _)| m.navigator())\n    }\n\n    fn location(&self) -> Option<Location> {\n        self.context::<LocationContext>(Callback::from(|_| {}))\n            .map(|(m, _)| m.location())\n    }\n\n    fn route<R>(&self) -> Option<R>\n    where\n        R: Routable + 'static,\n    {\n        let navigator = self.navigator()?;\n        let location = self.location()?;\n\n        let path = navigator.strip_basename(location.path().into());\n\n        R::recognize(&path)\n    }\n\n    fn add_location_listener(&self, cb: Callback<Location>) -> Option<LocationHandle> {\n        self.context::<LocationContext>(Callback::from(move |m: LocationContext| {\n            cb.emit(m.location())\n        }))\n        .map(|(_, m)| LocationHandle { _inner: m })\n    }\n\n    fn add_navigator_listener(&self, cb: Callback<Navigator>) -> Option<NavigatorHandle> {\n        self.context::<NavigatorContext>(Callback::from(move |m: NavigatorContext| {\n            cb.emit(m.navigator())\n        }))\n        .map(|(_, m)| NavigatorHandle { _inner: m })\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/switch.rs",
    "content": "//! The [`Switch`] Component.\n\nuse yew::prelude::*;\n\nuse crate::prelude::*;\n\n/// Props for [`Switch`]\n#[derive(Properties, PartialEq, Clone)]\npub struct SwitchProps<R>\nwhere\n    R: Routable,\n{\n    /// Callback which returns [`Html`] to be rendered for the current route.\n    pub render: Callback<R, Html>,\n    #[prop_or_default]\n    pub pathname: Option<String>,\n}\n\n/// A Switch that dispatches route among variants of a [`Routable`].\n///\n/// When a route can't be matched, including when the path is matched but the deserialization fails,\n/// it looks for the route with `not_found` attribute.\n/// If such a route is provided, it redirects to the specified route.\n/// Otherwise `html! {}` is rendered and a message is logged to console\n/// stating that no route can be matched.\n/// See the [crate level document][crate] for more information.\n#[component]\npub fn Switch<R>(props: &SwitchProps<R>) -> Html\nwhere\n    R: Routable + 'static,\n{\n    let route = use_route::<R>();\n\n    let route = props\n        .pathname\n        .as_ref()\n        .and_then(|p| R::recognize(p))\n        .or(route);\n\n    match route {\n        Some(route) => props.render.emit(route),\n        None => {\n            tracing::warn!(\"no route matched\");\n            Html::default()\n        }\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/src/utils.rs",
    "content": "use std::cell::RefCell;\n\nuse wasm_bindgen::JsCast;\n\npub(crate) fn strip_slash_suffix(path: &str) -> &str {\n    path.strip_suffix('/').unwrap_or(path)\n}\n\nstatic BASE_URL_LOADED: std::sync::Once = std::sync::Once::new();\nthread_local! {\n    static BASE_URL: RefCell<Option<String>> = const { RefCell::new(None) };\n}\n\n// This exists so we can cache the base url. It costs us a `to_string` call instead of a DOM API\n// call. Considering base urls are generally short, it *should* be less expensive.\npub fn base_url() -> Option<String> {\n    BASE_URL_LOADED.call_once(|| {\n        BASE_URL.with(|val| {\n            *val.borrow_mut() = fetch_base_url();\n        })\n    });\n    BASE_URL.with(|it| it.borrow().as_ref().map(|it| it.to_string()))\n}\n\npub fn fetch_base_url() -> Option<String> {\n    match gloo::utils::document().query_selector(\"base[href]\") {\n        Ok(Some(base)) => {\n            let base = base.unchecked_into::<web_sys::HtmlBaseElement>().href();\n\n            let url = web_sys::Url::new(&base).unwrap();\n            let base = url.pathname();\n\n            let base = if base != \"/\" {\n                strip_slash_suffix(&base)\n            } else {\n                return None;\n            };\n\n            Some(base.to_string())\n        }\n        _ => None,\n    }\n}\n\n#[cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))]\npub fn compose_path(pathname: &str, query: &str) -> Option<String> {\n    gloo::utils::window()\n        .location()\n        .href()\n        .ok()\n        .and_then(|base| web_sys::Url::new_with_base(pathname, &base).ok())\n        .map(|url| {\n            url.set_search(query);\n            format!(\"{}{}\", url.pathname(), url.search())\n        })\n}\n\n#[cfg(any(not(target_arch = \"wasm32\"), target_os = \"wasi\"))]\npub fn compose_path(pathname: &str, query: &str) -> Option<String> {\n    let query = query.trim();\n\n    if !query.is_empty() {\n        Some(format!(\"{pathname}?{query}\"))\n    } else {\n        Some(pathname.to_owned())\n    }\n}\n\n// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#[cfg(all(\n    test,\n    target_arch = \"wasm32\",\n    any(target_os = \"unknown\", target_os = \"none\")\n))]\nmod tests {\n    use gloo::utils::document;\n    use wasm_bindgen_test::wasm_bindgen_test as test;\n    use yew_router::prelude::*;\n    use yew_router::utils::*;\n\n    wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);\n\n    #[derive(Debug, Clone, Copy, PartialEq, Routable)]\n    enum Routes {\n        #[at(\"/\")]\n        Home,\n        #[at(\"/no\")]\n        No,\n        #[at(\"/404\")]\n        NotFound,\n    }\n\n    #[test]\n    fn test_base_url() {\n        document().head().unwrap().set_inner_html(r#\"\"#);\n\n        assert_eq!(fetch_base_url(), None);\n\n        document()\n            .head()\n            .unwrap()\n            .set_inner_html(r#\"<base href=\"/base/\">\"#);\n        assert_eq!(fetch_base_url(), Some(\"/base\".to_string()));\n\n        document()\n            .head()\n            .unwrap()\n            .set_inner_html(r#\"<base href=\"/base\">\"#);\n        assert_eq!(fetch_base_url(), Some(\"/base\".to_string()));\n    }\n\n    #[test]\n    fn test_compose_path() {\n        assert_eq!(compose_path(\"/home\", \"\"), Some(\"/home\".to_string()));\n        assert_eq!(\n            compose_path(\"/path/to\", \"foo=bar\"),\n            Some(\"/path/to?foo=bar\".to_string())\n        );\n        assert_eq!(\n            compose_path(\"/events\", \"from=2019&to=2021\"),\n            Some(\"/events?from=2019&to=2021\".to_string())\n        );\n    }\n}\n"
  },
  {
    "path": "packages/yew-router/tests/basename.rs",
    "content": "// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#![cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n\nuse std::time::Duration;\n\nuse serde::{Deserialize, Serialize};\nuse wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\nuse yew::functional::component;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nmod utils;\nuse utils::*;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[derive(Serialize, Deserialize)]\nstruct Query {\n    foo: String,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Routable)]\nenum Routes {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/no/:id\")]\n    No { id: u32 },\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Properties, PartialEq, Clone)]\nstruct NoProps {\n    id: u32,\n}\n\n#[component(No)]\nfn no(props: &NoProps) -> Html {\n    let route = props.id.to_string();\n\n    let location = use_location().unwrap();\n\n    html! {\n        <>\n            <div id=\"result-params\">{ route }</div>\n            <div id=\"result-query\">{ location.query::<Query>().unwrap().foo }</div>\n        </>\n    }\n}\n\n#[component(Comp)]\nfn component() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let switch = move |routes| {\n        let navigator_clone = navigator.clone();\n        let replace_route = Callback::from(move |_| {\n            navigator_clone\n                .replace_with_query(\n                    &Routes::No { id: 2 },\n                    &Query {\n                        foo: \"bar\".to_string(),\n                    },\n                )\n                .unwrap();\n        });\n\n        let navigator_clone = navigator.clone();\n        let push_route = Callback::from(move |_| {\n            navigator_clone\n                .push_with_query(\n                    &Routes::No { id: 3 },\n                    &Query {\n                        foo: \"baz\".to_string(),\n                    },\n                )\n                .unwrap();\n        });\n\n        match routes {\n            Routes::Home => html! {\n                <>\n                    <div id=\"result\">{\"Home\"}</div>\n                    <button onclick={replace_route}>{\"replace a route\"}</button>\n                </>\n            },\n            Routes::No { id } => html! {\n                <>\n                    <No id={id} />\n                    <button onclick={push_route}>{\"push a route\"}</button>\n                </>\n            },\n            Routes::NotFound => html! { <div id=\"result\">{\"404\"}</div> },\n        }\n    };\n\n    html! {\n        <Switch<Routes> render={switch} />\n    }\n}\n\n#[component(Root)]\nfn root() -> Html {\n    html! {\n        <BrowserRouter basename=\"/base/\">\n            <Comp />\n        </BrowserRouter>\n    }\n}\n\n// all the tests are in place because document state isn't being reset between tests\n// different routes at the time of execution are set and it causes weird behavior (tests\n// failing randomly)\n// this test tests\n// - routing\n// - parameters in the path\n// - query parameters\n// - 404 redirects\n#[test]\nasync fn router_works() {\n    yew::Renderer::<Root>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\"Home\", obtain_result_by_id(\"result\"));\n\n    sleep(Duration::ZERO).await;\n\n    let initial_length = history_length();\n\n    sleep(Duration::ZERO).await;\n\n    click(\"button\"); // replacing the current route\n\n    sleep(Duration::ZERO).await;\n    assert_eq!(\"2\", obtain_result_by_id(\"result-params\"));\n    assert_eq!(\"bar\", obtain_result_by_id(\"result-query\"));\n    assert_eq!(initial_length, history_length());\n\n    click(\"button\"); // pushing a new route\n\n    sleep(Duration::ZERO).await;\n    assert_eq!(\"3\", obtain_result_by_id(\"result-params\"));\n    assert_eq!(\"baz\", obtain_result_by_id(\"result-query\"));\n    assert_eq!(initial_length + 1, history_length());\n}\n"
  },
  {
    "path": "packages/yew-router/tests/browser_router.rs",
    "content": "// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#![cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n\nuse std::time::Duration;\n\nuse serde::{Deserialize, Serialize};\nuse wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\nuse yew::functional::component;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nmod utils;\nuse utils::*;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[derive(Serialize, Deserialize)]\nstruct Query {\n    foo: String,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Routable)]\nenum Routes {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/no/:id\")]\n    No { id: u32 },\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Properties, PartialEq, Clone)]\nstruct NoProps {\n    id: u32,\n}\n\n#[component(No)]\nfn no(props: &NoProps) -> Html {\n    let route = props.id.to_string();\n\n    let location = use_location().unwrap();\n\n    html! {\n        <>\n            <div id=\"result-params\">{ route }</div>\n            <div id=\"result-query\">{ location.query::<Query>().unwrap().foo }</div>\n        </>\n    }\n}\n\n#[component(Comp)]\nfn component() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let switch = move |routes| {\n        let navigator_clone = navigator.clone();\n        let replace_route = Callback::from(move |_| {\n            navigator_clone\n                .replace_with_query(\n                    &Routes::No { id: 2 },\n                    &Query {\n                        foo: \"bar\".to_string(),\n                    },\n                )\n                .unwrap();\n        });\n\n        let navigator_clone = navigator.clone();\n        let push_route = Callback::from(move |_| {\n            navigator_clone\n                .push_with_query(\n                    &Routes::No { id: 3 },\n                    &Query {\n                        foo: \"baz\".to_string(),\n                    },\n                )\n                .unwrap();\n        });\n\n        match routes {\n            Routes::Home => html! {\n                <>\n                    <div id=\"result\">{\"Home\"}</div>\n                    <button onclick={replace_route}>{\"replace a route\"}</button>\n                </>\n            },\n            Routes::No { id } => html! {\n                <>\n                    <No id={id} />\n                    <button onclick={push_route}>{\"push a route\"}</button>\n                </>\n            },\n            Routes::NotFound => html! { <div id=\"result\">{\"404\"}</div> },\n        }\n    };\n\n    html! {\n        <Switch<Routes> render={switch} />\n    }\n}\n\n#[component(Root)]\nfn root() -> Html {\n    html! {\n        <BrowserRouter>\n            <Comp />\n        </BrowserRouter>\n    }\n}\n\n// all the tests are in place because document state isn't being reset between tests\n// different routes at the time of execution are set and it causes weird behavior (tests\n// failing randomly)\n// this test tests\n// - routing\n// - parameters in the path\n// - query parameters\n// - 404 redirects\n#[test]\nasync fn router_works() {\n    yew::Renderer::<Root>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\"Home\", obtain_result_by_id(\"result\"));\n\n    sleep(Duration::ZERO).await;\n\n    let initial_length = history_length();\n\n    sleep(Duration::ZERO).await;\n\n    click(\"button\"); // replacing the current route\n\n    sleep(Duration::ZERO).await;\n    assert_eq!(\"2\", obtain_result_by_id(\"result-params\"));\n    assert_eq!(\"bar\", obtain_result_by_id(\"result-query\"));\n    assert_eq!(initial_length, history_length());\n\n    click(\"button\"); // pushing a new route\n\n    sleep(Duration::ZERO).await;\n    assert_eq!(\"3\", obtain_result_by_id(\"result-params\"));\n    assert_eq!(\"baz\", obtain_result_by_id(\"result-query\"));\n    assert_eq!(initial_length + 1, history_length());\n}\n"
  },
  {
    "path": "packages/yew-router/tests/hash_router.rs",
    "content": "// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#![cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n\nuse std::time::Duration;\n\nuse serde::{Deserialize, Serialize};\nuse wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\nuse yew::functional::component;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nmod utils;\nuse utils::*;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[derive(Serialize, Deserialize)]\nstruct Query {\n    foo: String,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Routable)]\nenum Routes {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/no/:id\")]\n    No { id: u32 },\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Properties, PartialEq, Clone)]\nstruct NoProps {\n    id: u32,\n}\n\n#[component(No)]\nfn no(props: &NoProps) -> Html {\n    let route = props.id.to_string();\n\n    let location = use_location().unwrap();\n\n    html! {\n        <>\n            <div id=\"result-params\">{ route }</div>\n            <div id=\"result-query\">{ location.query::<Query>().unwrap().foo }</div>\n        </>\n    }\n}\n\n#[component(Comp)]\nfn component() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let switch = move |routes| {\n        let navigator_clone = navigator.clone();\n        let replace_route = Callback::from(move |_| {\n            navigator_clone\n                .replace_with_query(\n                    &Routes::No { id: 2 },\n                    &Query {\n                        foo: \"bar\".to_string(),\n                    },\n                )\n                .unwrap();\n        });\n\n        let navigator_clone = navigator.clone();\n        let push_route = Callback::from(move |_| {\n            navigator_clone\n                .push_with_query(\n                    &Routes::No { id: 3 },\n                    &Query {\n                        foo: \"baz\".to_string(),\n                    },\n                )\n                .unwrap();\n        });\n\n        match routes {\n            Routes::Home => html! {\n                <>\n                    <div id=\"result\">{\"Home\"}</div>\n                    <button onclick={replace_route}>{\"replace a route\"}</button>\n                </>\n            },\n            Routes::No { id } => html! {\n                <>\n                    <No id={id} />\n                    <button onclick={push_route}>{\"push a route\"}</button>\n                </>\n            },\n            Routes::NotFound => html! { <div id=\"result\">{\"404\"}</div> },\n        }\n    };\n\n    html! {\n        <Switch<Routes> render={switch} />\n    }\n}\n\n#[component(Root)]\nfn root() -> Html {\n    html! {\n        <HashRouter>\n            <Comp />\n        </HashRouter>\n    }\n}\n\n// all the tests are in place because document state isn't being reset between tests\n// different routes at the time of execution are set and it causes weird behavior (tests\n// failing randomly)\n// this test tests\n// - routing\n// - parameters in the path\n// - query parameters\n// - 404 redirects\n#[test]\nasync fn router_works() {\n    yew::Renderer::<Root>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\"Home\", obtain_result_by_id(\"result\"));\n\n    sleep(Duration::ZERO).await;\n\n    let initial_length = history_length();\n\n    sleep(Duration::ZERO).await;\n\n    click(\"button\"); // replacing the current route\n\n    sleep(Duration::ZERO).await;\n    assert_eq!(\"2\", obtain_result_by_id(\"result-params\"));\n    assert_eq!(\"bar\", obtain_result_by_id(\"result-query\"));\n    assert_eq!(initial_length, history_length());\n\n    click(\"button\"); // pushing a new route\n\n    sleep(Duration::ZERO).await;\n    assert_eq!(\"3\", obtain_result_by_id(\"result-params\"));\n    assert_eq!(\"baz\", obtain_result_by_id(\"result-query\"));\n    assert_eq!(initial_length + 1, history_length());\n}\n"
  },
  {
    "path": "packages/yew-router/tests/link.rs",
    "content": "// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#![cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n\nuse std::sync::atomic::{AtomicU8, Ordering};\nuse std::time::Duration;\n\nuse gloo::utils::window;\nuse js_sys::{JsString, Object, Reflect};\nuse serde::{Deserialize, Serialize};\nuse wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\nuse yew::functional::component;\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nmod utils;\nuse utils::*;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[derive(Clone, Serialize, Deserialize, PartialEq)]\nstruct PageParam {\n    page: i32,\n}\n\n#[derive(Clone, Serialize, Deserialize, PartialEq)]\nstruct SearchParams {\n    q: String,\n    lang: Option<String>,\n}\n\nimpl SearchParams {\n    fn new(q: &str) -> Self {\n        Self {\n            q: q.to_string(),\n            lang: None,\n        }\n    }\n\n    fn new_with_lang(q: &str, lang: &str) -> Self {\n        Self {\n            q: q.to_string(),\n            lang: Some(lang.to_string()),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Routable)]\nenum Routes {\n    #[at(\"/posts\")]\n    Posts,\n    #[at(\"/search\")]\n    Search,\n}\n\n#[derive(PartialEq, Properties)]\nstruct NavigationMenuProps {\n    #[prop_or(None)]\n    assertion: Option<fn(&Navigator, &Location)>,\n}\n\n#[component(NavigationMenu)]\nfn navigation_menu(props: &NavigationMenuProps) -> Html {\n    let navigator = use_navigator().unwrap();\n    let location = use_location().unwrap();\n    if let Some(assertion) = props.assertion {\n        assertion(&navigator, &location);\n    }\n\n    html! {\n        <ul>\n            <li class=\"posts\">\n                <Link<Routes> to={Routes::Posts}>\n                    { \"Posts without parameters\" }\n                </Link<Routes>>\n            </li>\n            <li class=\"posts-page-2\">\n                <Link<Routes, PageParam> to={Routes::Posts} query={Some(PageParam { page: 2 })}>\n                    { \"Posts of 2nd page\" }\n                </Link<Routes, PageParam>>\n            </li>\n            <li class=\"search\">\n                <Link<Routes> to={Routes::Search}>\n                    { \"Search withfout parameters\" }\n                </Link<Routes>>\n            </li>\n            <li class=\"search-q\">\n                <Link<Routes, SearchParams> to={Routes::Search} query={Some(SearchParams::new(\"Rust\"))}>\n                    { \"Search with keyword parameter\" }\n                </Link<Routes, SearchParams>>\n            </li>\n            <li class=\"search-q-lang\">\n                <Link<Routes, SearchParams> to={Routes::Search} query={Some(SearchParams::new_with_lang(\"Rust\", \"en_US\"))}>\n                    { \"Search with keyword and language parameters\" }\n                </Link<Routes, SearchParams>>\n            </li>\n        </ul>\n    }\n}\n\n#[component(RootForBrowserRouter)]\nfn root_for_browser_router() -> Html {\n    html! {\n        <BrowserRouter>\n            <NavigationMenu />\n        </BrowserRouter>\n    }\n}\n\nasync fn link_in_browser_router() {\n    let div = gloo::utils::document().create_element(\"div\").unwrap();\n    let _ = div.set_attribute(\"id\", \"browser-router\");\n    let _ = gloo::utils::body().append_child(&div);\n    let handle = yew::Renderer::<RootForBrowserRouter>::with_root(div).render();\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\"/posts\", link_href(\"#browser-router ul > li.posts > a\"));\n    assert_eq!(\n        \"/posts?page=2\",\n        link_href(\"#browser-router ul > li.posts-page-2 > a\")\n    );\n\n    assert_eq!(\"/search\", link_href(\"#browser-router ul > li.search > a\"));\n    assert_eq!(\n        \"/search?q=Rust\",\n        link_href(\"#browser-router ul > li.search-q > a\")\n    );\n    assert_eq!(\n        \"/search?q=Rust&lang=en_US\",\n        link_href(\"#browser-router ul > li.search-q-lang > a\")\n    );\n\n    handle.destroy();\n}\n\n#[derive(PartialEq, Properties)]\nstruct BasenameProps {\n    basename: Option<String>,\n    assertion: fn(&Navigator, &Location),\n}\n\n#[component(RootForBasename)]\nfn root_for_basename(props: &BasenameProps) -> Html {\n    html! {\n        <BrowserRouter basename={props.basename.clone()}>\n            <NavigationMenu assertion={props.assertion}/>\n        </BrowserRouter>\n    }\n}\n\nasync fn link_with_basename(correct_initial_path: bool) {\n    if correct_initial_path {\n        let cookie = Object::new();\n        Reflect::set(&cookie, &JsString::from(\"foo\"), &JsString::from(\"bar\")).unwrap();\n        window()\n            .history()\n            .unwrap()\n            .replace_state_with_url(&cookie, \"\", Some(\"/base/\"))\n            .unwrap();\n    }\n\n    static RENDERS: AtomicU8 = AtomicU8::new(0);\n    RENDERS.store(0, Ordering::Relaxed);\n\n    let div = gloo::utils::document().create_element(\"div\").unwrap();\n    let _ = div.set_attribute(\"id\", \"with-basename\");\n    let _ = gloo::utils::body().append_child(&div);\n\n    let mut handle = yew::Renderer::<RootForBasename>::with_root_and_props(\n        div,\n        BasenameProps {\n            basename: Some(\"/base/\".to_owned()),\n            assertion: |navigator, location| {\n                RENDERS.fetch_add(1, Ordering::Relaxed);\n                assert_eq!(navigator.basename(), Some(\"/base\"));\n                assert_eq!(location.path(), \"/base/\");\n            },\n        },\n    )\n    .render();\n\n    sleep(Duration::ZERO).await;\n\n    if correct_initial_path {\n        // If the initial path was correct, the router shouldn't have mutated the history.\n        assert_eq!(\n            Reflect::get(\n                &window().history().unwrap().state().unwrap(),\n                &JsString::from(\"foo\")\n            )\n            .unwrap()\n            .as_string()\n            .as_deref(),\n            Some(\"bar\")\n        );\n    }\n\n    assert_eq!(\n        \"/base/\",\n        gloo::utils::window().location().pathname().unwrap()\n    );\n\n    assert_eq!(\"/base/posts\", link_href(\"#with-basename ul > li.posts > a\"));\n    assert_eq!(\n        \"/base/posts?page=2\",\n        link_href(\"#with-basename ul > li.posts-page-2 > a\")\n    );\n\n    assert_eq!(\n        \"/base/search\",\n        link_href(\"#with-basename ul > li.search > a\")\n    );\n    assert_eq!(\n        \"/base/search?q=Rust\",\n        link_href(\"#with-basename ul > li.search-q > a\")\n    );\n    assert_eq!(\n        \"/base/search?q=Rust&lang=en_US\",\n        link_href(\"#with-basename ul > li.search-q-lang > a\")\n    );\n\n    // Some(a) -> Some(b)\n    handle.update(BasenameProps {\n        basename: Some(\"/bayes/\".to_owned()),\n        assertion: |navigator, location| {\n            RENDERS.fetch_add(1, Ordering::Relaxed);\n            assert_eq!(navigator.basename(), Some(\"/bayes\"));\n            assert_eq!(location.path(), \"/bayes/\");\n        },\n    });\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\n        \"/bayes/\",\n        gloo::utils::window().location().pathname().unwrap()\n    );\n\n    assert_eq!(\n        \"/bayes/posts\",\n        link_href(\"#with-basename ul > li.posts > a\")\n    );\n\n    // Some -> None\n    handle.update(BasenameProps {\n        basename: None,\n        assertion: |navigator, location| {\n            RENDERS.fetch_add(1, Ordering::Relaxed);\n            assert_eq!(navigator.basename(), None);\n            assert_eq!(location.path(), \"/\");\n        },\n    });\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\"/\", gloo::utils::window().location().pathname().unwrap());\n\n    assert_eq!(\"/posts\", link_href(\"#with-basename ul > li.posts > a\"));\n\n    // None -> Some\n    handle.update(BasenameProps {\n        basename: Some(\"/bass/\".to_string()),\n        assertion: |navigator, location| {\n            RENDERS.fetch_add(1, Ordering::Relaxed);\n            assert_eq!(navigator.basename(), Some(\"/bass\"));\n            assert_eq!(location.path(), \"/bass/\");\n        },\n    });\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\n        \"/bass/\",\n        gloo::utils::window().location().pathname().unwrap()\n    );\n\n    assert_eq!(\"/bass/posts\", link_href(\"#with-basename ul > li.posts > a\"));\n\n    handle.destroy();\n\n    // 1 initial, 1 rerender after initial, 3 props changes\n    assert_eq!(RENDERS.load(Ordering::Relaxed), 5);\n}\n\n#[component(RootForHashRouter)]\nfn root_for_hash_router() -> Html {\n    html! {\n        <HashRouter>\n            <NavigationMenu />\n        </HashRouter>\n    }\n}\n\nasync fn link_in_hash_router() {\n    let div = gloo::utils::document().create_element(\"div\").unwrap();\n    let _ = div.set_attribute(\"id\", \"hash-router\");\n    let _ = gloo::utils::body().append_child(&div);\n    let handle = yew::Renderer::<RootForHashRouter>::with_root(div).render();\n\n    sleep(Duration::ZERO).await;\n\n    assert_eq!(\"#/posts\", link_href(\"#hash-router ul > li.posts > a\"));\n    assert_eq!(\n        \"#/posts?page=2\",\n        link_href(\"#hash-router ul > li.posts-page-2 > a\")\n    );\n\n    assert_eq!(\"#/search\", link_href(\"#hash-router ul > li.search > a\"));\n    assert_eq!(\n        \"#/search?q=Rust\",\n        link_href(\"#hash-router ul > li.search-q > a\")\n    );\n    assert_eq!(\n        \"#/search?q=Rust&lang=en_US\",\n        link_href(\"#hash-router ul > li.search-q-lang > a\")\n    );\n\n    handle.destroy();\n}\n\n// These cannot be run in concurrently because they all read/write the URL.\n#[test]\nasync fn sequential_tests() {\n    link_in_hash_router().await;\n    link_in_browser_router().await;\n    link_with_basename(false).await;\n    link_with_basename(true).await;\n}\n"
  },
  {
    "path": "packages/yew-router/tests/router_unit_tests.rs",
    "content": "// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#![cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n\nuse wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\nuse yew_router::prelude::*;\n\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[test]\nfn router_always_404() {\n    #[derive(Routable, Debug, Clone, PartialEq)]\n    enum AppRoute {\n        #[at(\"/\")]\n        Home,\n        #[at(\"/:id\")]\n        Article { id: u64 },\n        #[at(\"/404\")]\n        #[not_found]\n        NotFound,\n    }\n\n    assert_eq!(\n        Some(AppRoute::NotFound),\n        AppRoute::recognize(\"/not/matched/route\")\n    );\n    assert_eq!(\n        Some(AppRoute::NotFound),\n        AppRoute::recognize(\"/not-matched-route\")\n    );\n}\n\n#[test]\nfn router_trailing_slash() {\n    #[derive(Routable, Debug, Clone, PartialEq)]\n    enum AppRoute {\n        #[at(\"/\")]\n        Home,\n        #[at(\"/category/:name/\")]\n        Category { name: String },\n        #[at(\"/:id\")]\n        Article { id: u64 },\n        #[at(\"/404\")]\n        #[not_found]\n        NotFound,\n    }\n\n    assert_eq!(\n        Some(AppRoute::Category {\n            name: \"cooking-recipes\".to_string()\n        }),\n        AppRoute::recognize(\"/category/cooking-recipes/\")\n    );\n}\n\n#[test]\nfn router_url_encoding() {\n    #[derive(Routable, Debug, Clone, PartialEq)]\n    enum AppRoute {\n        #[at(\"/\")]\n        Root,\n        #[at(\"/search/:query\")]\n        Search { query: String },\n    }\n\n    assert_eq!(\n        yew_router::__macro::decode_for_url(\"/search/a%2Fb/\").unwrap(),\n        \"/search/a/b/\"\n    );\n\n    assert_eq!(\n        Some(AppRoute::Search {\n            query: \"a/b\".to_string()\n        }),\n        AppRoute::recognize(\"/search/a%2Fb/\")\n    );\n}\n\n#[test]\nfn router_wildcard_encoding() {\n    #[derive(Routable, Debug, Clone, PartialEq)]\n    enum AppRoute {\n        #[at(\"/\")]\n        Root,\n        #[at(\"/file/*path\")]\n        File { path: String },\n        #[at(\"/user/:id\")]\n        User { id: String },\n    }\n\n    let route = AppRoute::File {\n        path: \"docs/guides/getting-started.md\".to_string(),\n    };\n    assert_eq!(route.to_path(), \"/file/docs/guides/getting-started.md\");\n\n    assert_eq!(\n        Some(AppRoute::File {\n            path: \"docs/guides/getting-started.md\".to_string()\n        }),\n        AppRoute::recognize(\"/file/docs/guides/getting-started.md\")\n    );\n\n    let route_special = AppRoute::File {\n        path: \"docs/my file (1)/notes.txt\".to_string(),\n    };\n    assert_eq!(\n        route_special.to_path(),\n        \"/file/docs/my%20file%20%281%29/notes.txt\"\n    );\n\n    assert_eq!(\n        Some(AppRoute::File {\n            path: \"docs/my file (1)/notes.txt\".to_string()\n        }),\n        AppRoute::recognize(\"/file/docs/my%20file%20%281%29/notes.txt\")\n    );\n\n    let user_route = AppRoute::User {\n        id: \"a/b\".to_string(),\n    };\n    assert_eq!(user_route.to_path(), \"/user/a%2Fb\");\n}\n"
  },
  {
    "path": "packages/yew-router/tests/url_encoded_routes.rs",
    "content": "// TODO: remove the cfg after wasm-bindgen-test stops emitting the function unconditionally\n#![cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))]\n\nuse std::time::Duration;\n\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\nmod utils;\nuse utils::*;\nuse wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};\nwasm_bindgen_test_configure!(run_in_browser);\n\n#[derive(Routable, Debug, Clone, PartialEq)]\nenum AppRoute {\n    #[at(\"/\")]\n    Root,\n    #[at(\"/search/:query\")]\n    Search { query: String },\n}\n\n#[component]\nfn Comp() -> Html {\n    let switch = move |routes: AppRoute| match routes {\n        AppRoute::Root => html! {\n            <>\n                <h1>{ \"Root\" }</h1>\n                <Link<AppRoute> to={AppRoute::Search { query: \"a/b\".to_string() }}>\n                    {\"Click me\"}\n                </Link<AppRoute>>\n            </>\n        },\n        AppRoute::Search { query } => html! {\n            <p id=\"q\">{ query }</p>\n        },\n    };\n    html! {\n        <Switch<AppRoute> render={switch} />\n    }\n}\n\n#[component(Root)]\nfn root() -> Html {\n    html! {\n        <BrowserRouter>\n            <Comp />\n        </BrowserRouter>\n    }\n}\n\n#[test]\nasync fn url_encoded_roundtrip() {\n    yew::Renderer::<Root>::with_root(gloo::utils::document().get_element_by_id(\"output\").unwrap())\n        .render();\n    sleep(Duration::ZERO).await;\n    click(\"a\");\n    sleep(Duration::ZERO).await;\n    let res = obtain_result_by_id(\"q\");\n    assert_eq!(res, \"a/b\");\n\n    assert_eq!(\n        gloo::utils::window().location().pathname().unwrap(),\n        \"/search/a%2Fb\"\n    )\n}\n"
  },
  {
    "path": "packages/yew-router/tests/utils.rs",
    "content": "use wasm_bindgen::JsCast;\n\n#[allow(dead_code)]\npub fn obtain_result_by_id(id: &str) -> String {\n    gloo::utils::document()\n        .get_element_by_id(id)\n        .expect(\"No result found. Most likely, the application crashed and burned\")\n        .inner_html()\n}\n\n#[allow(dead_code)]\npub fn click(selector: &str) {\n    gloo::utils::document()\n        .query_selector(selector)\n        .unwrap()\n        .unwrap()\n        .dyn_into::<web_sys::HtmlElement>()\n        .unwrap()\n        .click();\n}\n\n#[allow(dead_code)]\npub fn history_length() -> u32 {\n    gloo::utils::window()\n        .history()\n        .expect(\"No history found\")\n        .length()\n        .expect(\"No history length found\")\n}\n\n#[allow(dead_code)]\npub fn link_href(selector: &str) -> String {\n    gloo::utils::document()\n        .query_selector(selector)\n        .expect(\"Failed to run query selector\")\n        .unwrap_or_else(|| panic!(\"No such link: {selector}\"))\n        .get_attribute(\"href\")\n        .expect(\"No href attribute\")\n}\n"
  },
  {
    "path": "packages/yew-router-macro/Cargo.toml",
    "content": "[package]\nname = \"yew-router-macro\"\nversion = \"0.20.0\"\nauthors = [\"Hamza <muhammadhamza1311@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"Contains macros used with yew-router\"\nrepository = \"https://github.com/yewstack/yew\"\nrust-version = \"1.84.0\"\n\n[lib]\nproc-macro = true\n\n[dependencies]\nproc-macro2.workspace = true\nquote.workspace = true\nsyn = { workspace = true, features = [\"full\",\"extra-traits\"] }\n\n[dev-dependencies]\nrustversion.workspace = true\ntrybuild = { workspace = true }\nyew-router = { path = \"../yew-router\" }\n"
  },
  {
    "path": "packages/yew-router-macro/Makefile.toml",
    "content": "[tasks.test]\nclear = true\ntoolchain = \"1.84.0\"\ncommand = \"cargo\"\nargs = [\"test\"]\n\n[tasks.test-overwrite]\nextend = \"test\"\nenv = { TRYBUILD = \"overwrite\" }\n"
  },
  {
    "path": "packages/yew-router-macro/release.toml",
    "content": "tag = false\n"
  },
  {
    "path": "packages/yew-router-macro/src/lib.rs",
    "content": "mod routable_derive;\nuse routable_derive::{routable_derive_impl, Routable};\nuse syn::parse_macro_input;\n\n/// Derive macro used to mark an enum as Routable.\n///\n/// This macro can only be used on enums. Every variant of the macro needs to be marked\n/// with the `at` attribute to specify the URL of the route. It generates an implementation of\n///  `yew_router::Routable` trait and `const`s for the routes passed which are used with `Route`\n/// component.\n///\n/// # Example\n///\n/// ```\n/// # use yew_router::Routable;\n/// #[derive(Debug, Clone, Copy, PartialEq, Routable)]\n/// enum Routes {\n///     #[at(\"/\")]\n///     Home,\n///     #[at(\"/secure\")]\n///     Secure,\n///     #[at(\"/404\")]\n///     NotFound,\n/// }\n/// ```\n#[proc_macro_derive(Routable, attributes(at, not_found))]\npub fn routable_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {\n    let input = parse_macro_input!(input as Routable);\n    routable_derive_impl(input).into()\n}\n"
  },
  {
    "path": "packages/yew-router-macro/src/routable_derive.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::quote;\nuse syn::parse::{Parse, ParseStream};\nuse syn::punctuated::Punctuated;\nuse syn::spanned::Spanned;\nuse syn::{Data, DeriveInput, Fields, Ident, LitStr, Variant};\n\nconst AT_ATTR_IDENT: &str = \"at\";\nconst NOT_FOUND_ATTR_IDENT: &str = \"not_found\";\n\npub struct Routable {\n    ident: Ident,\n    ats: Vec<LitStr>,\n    variants: Punctuated<Variant, syn::token::Comma>,\n    not_found_route: Option<Ident>,\n}\n\nimpl Parse for Routable {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let DeriveInput { ident, data, .. } = input.parse()?;\n\n        let data = match data {\n            Data::Enum(data) => data,\n            Data::Struct(s) => {\n                return Err(syn::Error::new(\n                    s.struct_token.span(),\n                    \"expected enum, found struct\",\n                ))\n            }\n            Data::Union(u) => {\n                return Err(syn::Error::new(\n                    u.union_token.span(),\n                    \"expected enum, found union\",\n                ))\n            }\n        };\n\n        let (not_found_route, ats) = parse_variants_attributes(&data.variants)?;\n\n        Ok(Self {\n            ident,\n            variants: data.variants,\n            ats,\n            not_found_route,\n        })\n    }\n}\n\nfn parse_variants_attributes(\n    variants: &Punctuated<Variant, syn::token::Comma>,\n) -> syn::Result<(Option<Ident>, Vec<LitStr>)> {\n    let mut not_founds = vec![];\n    let mut ats: Vec<LitStr> = vec![];\n\n    let mut not_found_attrs = vec![];\n\n    for variant in variants.iter() {\n        if let Fields::Unnamed(ref field) = variant.fields {\n            return Err(syn::Error::new(\n                field.span(),\n                \"only named fields are supported\",\n            ));\n        }\n\n        let attrs = &variant.attrs;\n        let at_attrs = attrs\n            .iter()\n            .filter(|attr| attr.path().is_ident(AT_ATTR_IDENT))\n            .collect::<Vec<_>>();\n\n        let attr = match at_attrs.len() {\n            1 => *at_attrs.first().unwrap(),\n            0 => {\n                return Err(syn::Error::new(\n                    variant.span(),\n                    format!(\"{AT_ATTR_IDENT} attribute must be present on every variant\"),\n                ))\n            }\n            _ => {\n                return Err(syn::Error::new_spanned(\n                    quote! { #(#at_attrs)* },\n                    format!(\"only one {AT_ATTR_IDENT} attribute must be present\"),\n                ))\n            }\n        };\n\n        let lit = attr.parse_args::<LitStr>()?;\n        let val = lit.value();\n\n        if val.find('#').is_some() {\n            return Err(syn::Error::new_spanned(\n                lit,\n                \"You cannot use `#` in your routes. Please consider `HashRouter` instead.\",\n            ));\n        }\n\n        if !val.starts_with('/') {\n            return Err(syn::Error::new_spanned(\n                lit,\n                \"relative paths are not supported at this moment.\",\n            ));\n        }\n\n        ats.push(lit);\n\n        for attr in attrs.iter() {\n            if attr.path().is_ident(NOT_FOUND_ATTR_IDENT) {\n                not_found_attrs.push(attr);\n                not_founds.push(variant.ident.clone())\n            }\n        }\n    }\n\n    if not_founds.len() > 1 {\n        return Err(syn::Error::new_spanned(\n            quote! { #(#not_found_attrs)* },\n            format!(\"there can only be one {NOT_FOUND_ATTR_IDENT}\"),\n        ));\n    }\n\n    Ok((not_founds.into_iter().next(), ats))\n}\n\nimpl Routable {\n    fn build_from_path(&self) -> TokenStream {\n        let from_path_matches = self.variants.iter().enumerate().map(|(i, variant)| {\n            let ident = &variant.ident;\n            let right = match &variant.fields {\n                Fields::Unit => quote! { Self::#ident },\n                Fields::Named(field) => {\n                    let fields = field.named.iter().map(|it| {\n                        // named fields have idents\n                        it.ident.as_ref().unwrap()\n                    });\n                    quote! { Self::#ident { #(#fields: {\n                        let param = params.get(stringify!(#fields))?;\n                        let param = &*::yew_router::__macro::decode_for_url(param).ok()?;\n                        let param = param.parse().ok()?;\n                        param\n                    },)* } }\n                }\n                Fields::Unnamed(_) => unreachable!(), // already checked\n            };\n\n            let left = self.ats.get(i).unwrap();\n            quote! {\n                #left => ::std::option::Option::Some(#right)\n            }\n        });\n\n        quote! {\n            fn from_path(path: &str, params: &::std::collections::HashMap<&str, &str>) -> ::std::option::Option<Self> {\n                match path {\n                    #(#from_path_matches),*,\n                    _ => ::std::option::Option::None,\n                }\n            }\n        }\n    }\n\n    fn build_to_path(&self) -> TokenStream {\n        let to_path_matches = self.variants.iter().enumerate().map(|(i, variant)| {\n            let ident = &variant.ident;\n            let mut right = self.ats.get(i).unwrap().value();\n\n            match &variant.fields {\n                Fields::Unit => quote! { Self::#ident => ::std::string::ToString::to_string(#right) },\n                Fields::Named(field) => {\n                    let fields = field\n                        .named\n                        .iter()\n                        .map(|it| it.ident.as_ref().unwrap())\n                        .collect::<Vec<_>>();\n\n                    let mut wildcard_fields = std::collections::HashSet::new();\n                    for field in fields.iter() {\n                        if right.contains(&format!(\"*{field}\")) {\n                            wildcard_fields.insert((*field).clone());\n                        }\n                        // :param -> {param}\n                        // *param -> {param}\n                        // so we can pass it to `format!(\"...\", param)`\n                        right = right.replace(&format!(\":{field}\"), &format!(\"{{{field}}}\"));\n                        right = right.replace(&format!(\"*{field}\"), &format!(\"{{{field}}}\"));\n                    }\n\n                    let field_encodings = fields.iter().map(|field| {\n                        if wildcard_fields.contains(*field) {\n                            quote! {\n                                #field = ::yew_router::__macro::encode_path_for_url(&::std::format!(\"{}\", #field))\n                            }\n                        } else {\n                            quote! {\n                                #field = ::yew_router::__macro::encode_for_url(&::std::format!(\"{}\", #field))\n                            }\n                        }\n                    });\n\n                    quote! {\n                        Self::#ident { #(#fields),* } => ::std::format!(#right, #(#field_encodings),*)\n                    }\n                }\n                Fields::Unnamed(_) => unreachable!(), // already checked\n            }\n        });\n\n        quote! {\n            fn to_path(&self) -> ::std::string::String {\n                match self {\n                    #(#to_path_matches),*,\n                }\n            }\n        }\n    }\n}\n\npub fn routable_derive_impl(input: Routable) -> TokenStream {\n    let Routable {\n        ats,\n        not_found_route,\n        ident,\n        ..\n    } = &input;\n\n    let from_path = input.build_from_path();\n    let to_path = input.build_to_path();\n\n    let maybe_not_found_route = match not_found_route {\n        Some(route) => quote! { ::std::option::Option::Some(Self::#route) },\n        None => quote! { ::std::option::Option::None },\n    };\n\n    let maybe_default = match not_found_route {\n        Some(route) => {\n            quote! {\n                impl ::std::default::Default for #ident {\n                    fn default() -> Self {\n                        Self::#route\n                    }\n                }\n            }\n        }\n        None => TokenStream::new(),\n    };\n\n    quote! {\n        #[automatically_derived]\n        impl ::yew_router::Routable for #ident {\n            #from_path\n            #to_path\n\n            fn routes() -> ::std::vec::Vec<&'static str> {\n                ::std::vec![#(#ats),*]\n            }\n\n            fn not_found_route() -> ::std::option::Option<Self> {\n                #maybe_not_found_route\n            }\n\n            fn recognize(pathname: &str) -> ::std::option::Option<Self> {\n                ::std::thread_local! {\n                    static ROUTER: ::yew_router::__macro::Router = ::yew_router::__macro::build_router::<#ident>();\n                }\n                ROUTER.with(|router| ::yew_router::__macro::recognize_with_router(router, pathname))\n            }\n        }\n\n        #maybe_default\n    }\n}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/bad-ats-fail.rs",
    "content": "#[derive(yew_router::Routable)]\nenum Routes {\n    One,\n}\n\n#[derive(yew_router::Routable)]\nenum RoutesTwo {\n    #[at(\"/one\")]\n    #[at(\"/two\")]\n    One,\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/bad-ats-fail.stderr",
    "content": "error: at attribute must be present on every variant\n --> $DIR/bad-ats-fail.rs:3:5\n  |\n3 |     One,\n  |     ^^^\n\nerror: only one at attribute must be present\n --> $DIR/bad-ats-fail.rs:8:5\n  |\n8 | /     #[at(\"/one\")]\n9 | |     #[at(\"/two\")]\n  | |_________________^\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/invalid-not-found-fail.rs",
    "content": "#[derive(Debug, PartialEq, yew_router::Routable)]\nenum RoutesOne {\n    #[at(\"/\")]\n    #[not_found]\n    Home,\n    #[at(\"/404\")]\n    #[not_found]\n    NotFound,\n}\n\n#[derive(Debug, PartialEq, yew_router::Routable)]\nenum RoutesTwo {\n    #[at(\"/404\")]\n    #[not_found]\n    #[not_found]\n    NotFound,\n}\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/invalid-not-found-fail.stderr",
    "content": "error: there can only be one not_found\n --> $DIR/invalid-not-found-fail.rs:4:5\n  |\n4 | /     #[not_found]\n5 | |     Home,\n6 | |     #[at(\"/404\")]\n7 | |     #[not_found]\n  | |________________^\n\nerror: there can only be one not_found\n  --> $DIR/invalid-not-found-fail.rs:14:5\n   |\n14 | /     #[not_found]\n15 | |     #[not_found]\n   | |________________^\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/relative-path-fail.rs",
    "content": "#[derive(yew_router::Routable)]\nenum Routes {\n    #[at(\"one\")]\n    One,\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/relative-path-fail.stderr",
    "content": "error: relative paths are not supported at this moment.\n --> tests/routable_derive/relative-path-fail.rs:3:10\n  |\n3 |     #[at(\"one\")]\n  |          ^^^^^\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/route-with-hash-fail.rs",
    "content": "#[derive(yew_router::Routable)]\nenum Routes {\n    #[at(\"/#/one\")]\n    One,\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/route-with-hash-fail.stderr",
    "content": "error: You cannot use `#` in your routes. Please consider `HashRouter` instead.\n --> tests/routable_derive/route-with-hash-fail.rs:3:10\n  |\n3 |     #[at(\"/#/one\")]\n  |          ^^^^^^^^\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/struct-fail.rs",
    "content": "#[derive(yew_router::Routable)]\nstruct Test {}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/struct-fail.stderr",
    "content": "error: expected enum, found struct\n --> $DIR/struct-fail.rs:2:1\n  |\n2 | struct Test {}\n  | ^^^^^^\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/unnamed-fields-fail.rs",
    "content": "#[derive(yew_router::Routable)]\nenum Routes {\n    #[at(\"/one/:two\")]\n    One(u32),\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/unnamed-fields-fail.stderr",
    "content": "error: only named fields are supported\n --> $DIR/unnamed-fields-fail.rs:4:8\n  |\n4 |     One(u32),\n  |        ^^^^^\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive/valid-pass.rs",
    "content": "#![no_implicit_prelude]\n\n#[derive(Debug, PartialEq, Clone, ::yew_router::Routable)]\nenum Routes {\n    #[at(\"/\")]\n    One,\n    #[at(\"/two/:id\")]\n    Two { id: u32 },\n    #[at(\"/:a/:b/*rest\")]\n    Three { a: u32, b: u32, rest: ::std::string::String },\n    #[at(\"/404\")]\n    #[not_found]\n    NotFound,\n}\n\n#[derive(Debug, PartialEq, Clone, ::yew_router::Routable)]\nenum MoreRoutes {\n    #[at(\"/subpath/*rest\")]\n    Subpath { rest: ::std::string::String },\n    #[at(\"/*all\")]\n    CatchAll { all: ::std::string::String },\n}\n\nfn main() {}\n"
  },
  {
    "path": "packages/yew-router-macro/tests/routable_derive_test.rs",
    "content": "#[allow(dead_code)]\n#[rustversion::attr(stable(1.84.0), test)]\nfn tests() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/routable_derive/*-pass.rs\");\n    t.compile_fail(\"tests/routable_derive/*-fail.rs\");\n}\n\nfn main() {}\n"
  },
  {
    "path": "release.toml",
    "content": "consolidate-commits = false\npre-release-commit-message = \"(cargo-release) version {{crate_name}}-v{{version}}\"\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "edition = \"2021\"\n\nformat_code_in_doc_comments = true\nwrap_comments = true\ncomment_width = 100 # same as default max_width\nnormalize_doc_attributes = true\nnormalize_comments = true\n\ncondense_wildcard_suffixes = true\nformat_strings = true\ngroup_imports = \"StdExternalCrate\"\nimports_granularity = \"Module\"\nreorder_impl_items = true\nuse_field_init_shorthand = true\n"
  },
  {
    "path": "tools/benchmark-core/Cargo.toml",
    "content": "[package]\nname = \"benchmark-core\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[[bench]]\nname = \"vnode\"\nharness = false\n\n[dependencies]\ndivan = \"0.1.14\"\nyew = { path = \"../../packages/yew\" }\n"
  },
  {
    "path": "tools/benchmark-core/benches/vnode.rs",
    "content": "use yew::prelude::*;\n\nfn main() {\n    divan::main();\n}\n\n#[function_component]\nfn Stuff(_: &()) -> Html {\n    html! {\n        <p>{\"A custom component\"}</p>\n    }\n}\n\n#[divan::bench(sample_size = 10000000)]\nfn vnode_clone(bencher: divan::Bencher) {\n    let html = html! {\n        <div class={classes!(\"hello-world\")}>\n            <span>{\"Hello\"}</span>\n            <strong style=\"color:red\">{\"World\"}</strong>\n            <Stuff />\n            <Suspense fallback={html!(\"Loading...\")}>\n                <Stuff />\n            </Suspense>\n        </div>\n    };\n\n    bencher.bench_local(move || {\n        let _ = divan::black_box(html.clone());\n    });\n}\n"
  },
  {
    "path": "tools/benchmark-hooks/.gitignore",
    "content": "node_modules\n/target\n/bundled-dist\n\n"
  },
  {
    "path": "tools/benchmark-hooks/Cargo.toml",
    "content": "[package]\nname = \"js-framework-benchmark-yew-hooks\"\nversion = \"1.0.0\"\nauthors = [\"Julius Lungys <juliuslungys@gmail.com>\"]\nedition = \"2021\"\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nrand = { workspace = true, features = [\"small_rng\"] }\ngetrandom = { workspace = true }\nwasm-bindgen.workspace = true\nweb-sys = { workspace = true, features = [\"Window\"]}\nyew = { version = \"0.23.0\", features = [\"csr\"], path = \"../../packages/yew\" }\n\n[package.metadata.wasm-pack.profile.release]\nwasm-opt = ['-O4']\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "tools/benchmark-hooks/Makefile.toml",
    "content": "# Extends the root Makefile.toml\n\n[tasks.doc-test]\ncommand = \"echo\"\nargs = [\"No doctests run for benchmark-hooks\"]"
  },
  {
    "path": "tools/benchmark-hooks/README.md",
    "content": "Copied from https://github.com/krausest/js-framework-benchmark\n\nIt should ideally stay/be updated to always match what is on https://github.com/krausest/js-framework-benchmark\nExcept the fixes required to tun using unreleased yew version.\n\nIf you want to improve benchmarks, consider first opening a PR to https://github.com/krausest/js-framework-benchmark and only then sync this package with it.\n"
  },
  {
    "path": "tools/benchmark-hooks/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Yew-Hooks</title>\n    <link href=\"/css/currentStyle.css\" rel=\"stylesheet\"/>\n    <base href=\"bundled-dist/\"></base>\n  </head>\n  <body>\n    <div id='main'></div>\n    <script type=\"module\">\n      import init from './js-framework-benchmark-yew-hooks.js';\n      init('./js-framework-benchmark-yew-hooks_bg.wasm');\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tools/benchmark-hooks/package.json",
    "content": "{\n  \"name\": \"js-framework-benchmark-keyed-yew-hooks\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Benchmark for Yew Hooks\",\n  \"license\": \"ISC\",\n  \"js-framework-benchmark\": {\n    \"frameworkVersion\": \"latest\",\n    \"frameworkHomeURL\": \"https://yew.rs/\",\n    \"issues\": [\n      1139\n    ]\n  },\n  \"scripts\": {\n    \"build-prod\": \"echo This is a no-op. && echo Due to heavy dependencies, the generated javascript is already provided. && echo If you really want to rebuild from source use: && echo npm run build-prod-force\",\n    \"build-prod-force\": \"rustup target add wasm32-unknown-unknown && cargo install wasm-pack && npx build-prod-without-tools-install\",\n    \"build-prod-without-tools-install\": \"rimraf bundled-dist && wasm-pack build --release --target web --no-typescript --out-name js-framework-benchmark-yew-hooks --out-dir bundled-dist && cpr index.html bundled-dist/index.html && (cd bundled-dist && rimraf .gitignore README.md package.json)\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/krausest/js-framework-benchmark.git\"\n  },\n  \"devDependencies\": {\n    \"cpr\": \"^3.0.1\",\n    \"rimraf\": \"^2.6.3\"\n  },\n  \"dependencies\": {\n    \"js-framework-benchmark-keyed-yew-hooks\": \"file:\"\n  }\n}\n"
  },
  {
    "path": "tools/benchmark-hooks/src/lib.rs",
    "content": "use std::cmp::min;\nuse std::ops::Deref;\nuse std::rc::Rc;\n\nuse rand::prelude::*;\nuse wasm_bindgen::prelude::*;\nuse web_sys::window;\nuse yew::prelude::*;\n\nstatic ADJECTIVES: &[&str] = &[\n    \"pretty\",\n    \"large\",\n    \"big\",\n    \"small\",\n    \"tall\",\n    \"short\",\n    \"long\",\n    \"handsome\",\n    \"plain\",\n    \"quaint\",\n    \"clean\",\n    \"elegant\",\n    \"easy\",\n    \"angry\",\n    \"crazy\",\n    \"helpful\",\n    \"mushy\",\n    \"odd\",\n    \"unsightly\",\n    \"adorable\",\n    \"important\",\n    \"inexpensive\",\n    \"cheap\",\n    \"expensive\",\n    \"fancy\",\n];\n\nstatic COLOURS: &[&str] = &[\n    \"red\", \"yellow\", \"blue\", \"green\", \"pink\", \"brown\", \"purple\", \"brown\", \"white\", \"black\",\n    \"orange\",\n];\n\nstatic NOUNS: &[&str] = &[\n    \"table\", \"chair\", \"house\", \"bbq\", \"desk\", \"car\", \"pony\", \"cookie\", \"sandwich\", \"burger\",\n    \"pizza\", \"mouse\", \"keyboard\",\n];\n\n#[derive(Clone, PartialEq)]\nstruct RowData {\n    id: usize,\n    label: String,\n}\n\nimpl RowData {\n    fn new(id: usize, rng: &mut SmallRng) -> Self {\n        let adjective = *ADJECTIVES.choose(rng).unwrap();\n        let colour = *COLOURS.choose(rng).unwrap();\n        let noun = *NOUNS.choose(rng).unwrap();\n\n        let label = [adjective, colour, noun].join(\" \");\n\n        Self { id, label }\n    }\n}\n\nenum AppStateAction {\n    Run(usize),\n    Add(usize),\n    Update(usize),\n    Clear,\n    Swap,\n    Remove(usize),\n    Select(usize),\n}\n\n#[derive(Clone)]\nstruct AppState {\n    next_id: usize,\n    selected_id: Option<usize>,\n    rows: Vec<RowData>,\n    rng: SmallRng,\n}\n\nimpl Default for AppState {\n    fn default() -> Self {\n        Self {\n            rows: Vec::new(),\n            next_id: 1,\n            selected_id: None,\n            rng: SmallRng::from_os_rng(),\n        }\n    }\n}\n\nimpl Reducible for AppState {\n    type Action = AppStateAction;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        let mut new_state = self.deref().clone();\n        match action {\n            AppStateAction::Run(amount) => {\n                let rng = &mut new_state.rng;\n                let next_id = new_state.next_id;\n                let update_amount = min(amount, new_state.rows.len());\n                for index in 0..update_amount {\n                    new_state.rows[index] = RowData::new(next_id + index, rng);\n                }\n                new_state.rows.extend(\n                    (update_amount..amount).map(|index| RowData::new(next_id + index, rng)),\n                );\n                new_state.next_id += amount;\n            }\n            AppStateAction::Add(amount) => {\n                let rng = &mut new_state.rng;\n                let next_id = new_state.next_id;\n                new_state\n                    .rows\n                    .extend((0..amount).map(|index| RowData::new(next_id + index, rng)));\n                new_state.next_id += amount;\n            }\n            AppStateAction::Update(step) => {\n                for index in (0..new_state.rows.len()).step_by(step) {\n                    new_state.rows[index].label += \" !!!\";\n                }\n            }\n            AppStateAction::Clear => {\n                new_state.rows.clear();\n            }\n            AppStateAction::Swap => {\n                if new_state.rows.len() > 998 {\n                    new_state.rows.swap(1, 998);\n                }\n            }\n            AppStateAction::Remove(id) => {\n                if let Some(index) = new_state.rows.iter().position(|row| row.id == id) {\n                    new_state.rows.remove(index);\n                }\n            }\n            AppStateAction::Select(id) => {\n                new_state.selected_id = Some(id);\n            }\n        };\n\n        new_state.into()\n    }\n}\n\n#[function_component(App)]\nfn app() -> Html {\n    let state = use_reducer(AppState::default);\n\n    let selected_id = state.deref().selected_id;\n    let rows = state.deref().rows.clone();\n\n    let on_run = {\n        let state = state.clone();\n        Callback::from(move |amount| state.dispatch(AppStateAction::Run(amount)))\n    };\n    let on_add = {\n        let state = state.clone();\n        Callback::from(move |amount| state.dispatch(AppStateAction::Add(amount)))\n    };\n    let on_update = {\n        let state = state.clone();\n        Callback::from(move |amount| state.dispatch(AppStateAction::Update(amount)))\n    };\n    let on_clear = {\n        let state = state.clone();\n        Callback::from(move |_| state.dispatch(AppStateAction::Clear))\n    };\n    let on_swap = {\n        let state = state.clone();\n        Callback::from(move |_| state.dispatch(AppStateAction::Swap))\n    };\n    let on_select = {\n        let state = state.clone();\n        Callback::from(move |id| state.dispatch(AppStateAction::Select(id)))\n    };\n    let on_remove = Callback::from(move |id| state.dispatch(AppStateAction::Remove(id)));\n\n    let rows: Html = rows\n        .into_iter()\n        .map(move |row| {\n            let id = row.id;\n            html! {\n                <Row\n                    key={id}\n                    data={row}\n                    selected={selected_id == Some(id)}\n                    on_select={on_select.reform(move |_| id)}\n                    on_remove={on_remove.reform(move |_| id)}\n                />\n            }\n        })\n        .collect();\n\n    html! {\n        <div class=\"container\">\n            <Jumbotron\n                {on_run}\n                {on_add}\n                {on_update}\n                {on_clear}\n                {on_swap}\n            />\n            <table class=\"table table-hover table-striped test-data\">\n                <tbody id=\"tbody\">\n                    { rows }\n                </tbody>\n            </table>\n            <span class=\"preloadicon glyphicon glyphicon-remove\" aria-hidden=\"true\"></span>\n        </div>\n    }\n}\n\n#[derive(Properties, Clone, PartialEq)]\npub struct JumbotronProps {\n    pub on_run: Callback<usize>,\n    pub on_add: Callback<usize>,\n    pub on_update: Callback<usize>,\n    pub on_clear: Callback<()>,\n    pub on_swap: Callback<()>,\n}\n\n#[function_component(Jumbotron)]\nfn jumbotron(props: &JumbotronProps) -> Html {\n    html! {\n        <div class=\"jumbotron\">\n            <div class=\"row\">\n                <div class=\"col-md-6\">\n                    <h1>{ \"Yew-Hooks\" }</h1>\n                </div>\n                <div class=\"col-md-6\">\n                    <div class=\"row\">\n                        <div class=\"col-sm-6 smallpad\">\n                            <button type=\"button\" id=\"run\" class=\"btn btn-primary btn-block\" onclick={props.on_run.reform(|_| 1_000)}>{ \"Create 1,000 rows\" }</button>\n                        </div>\n                        <div class=\"col-sm-6 smallpad\">\n                            <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={props.on_run.reform(|_| 10_000)} id=\"runlots\">{ \"Create 10,000 rows\" }</button>\n                        </div>\n                        <div class=\"col-sm-6 smallpad\">\n                            <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={props.on_add.reform(|_| 1_000)} id=\"add\">{ \"Append 1,000 rows\" }</button>\n                        </div>\n                        <div class=\"col-sm-6 smallpad\">\n                            <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={props.on_update.reform(|_| 10)} id=\"update\">{ \"Update every 10th row\" }</button>\n                        </div>\n                        <div class=\"col-sm-6 smallpad\">\n                            <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={props.on_clear.reform(|_| ())} id=\"clear\">{ \"Clear\" }</button>\n                        </div>\n                        <div class=\"col-sm-6 smallpad\">\n                            <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={props.on_swap.reform(|_| ())} id=\"swaprows\">{ \"Swap Rows\" }</button>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    }\n}\n\n#[derive(Properties, Clone, PartialEq)]\nstruct RowProps {\n    on_select: Callback<MouseEvent>,\n    on_remove: Callback<MouseEvent>,\n    selected: bool,\n    data: RowData,\n}\n\n#[function_component(Row)]\nfn row(props: &RowProps) -> Html {\n    html! {\n        <tr class={if props.selected { \"danger\" } else  { \"\" }}>\n            <td class=\"col-md-1\">{ props.data.id }</td>\n            <td class=\"col-md-4\" onclick={props.on_select.clone()}>\n                <a class=\"lbl\">{ props.data.label.clone() }</a>\n            </td>\n            <td class=\"col-md-1\">\n                <a class=\"remove\" onclick={props.on_remove.clone()}>\n                    <span class=\"glyphicon glyphicon-remove remove\" aria-hidden=\"true\"></span>\n                </a>\n            </td>\n            <td class=\"col-md-6\"></td>\n        </tr>\n    }\n}\n\n#[wasm_bindgen(start)]\npub fn start() {\n    let document = window().unwrap().document().unwrap();\n    let mount_el = document.query_selector(\"#main\").unwrap().unwrap();\n    yew::Renderer::<App>::with_root(mount_el).render();\n}\n"
  },
  {
    "path": "tools/benchmark-ssr/Cargo.toml",
    "content": "[package]\nname = \"benchmark-ssr\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nyew = { path = \"../../packages/yew\", features = [\"ssr\"] }\nfunction_router = { path = \"../../examples/function_router\" }\ntokio = { workspace = true, features = [\"macros\", \"rt-multi-thread\", \"time\"] }\naverage = \"0.16.0\"\ntabled = \"0.20.0\"\nindicatif = \"0.18.4\"\nserde = { workspace = true, features = [\"derive\"] }\nserde_json.workspace = true\nclap = { workspace = true }\n\n[target.'cfg(unix)'.dependencies]\njemallocator = \"0.5.4\"\n"
  },
  {
    "path": "tools/benchmark-ssr/src/main.rs",
    "content": "use std::collections::HashMap;\nuse std::fs::File;\nuse std::path::PathBuf;\nuse std::time::{Duration, Instant};\n\nuse average::Variance;\nuse clap::Parser;\nuse function_router::{ServerApp, ServerAppProps};\nuse indicatif::{ProgressBar, ProgressStyle};\nuse serde::{Deserialize, Serialize};\nuse tabled::settings::Style;\nuse tabled::{Table, Tabled};\nuse tokio::task::{spawn_local, LocalSet};\nuse yew::platform::time::sleep;\nuse yew::prelude::*;\n\n#[cfg(unix)]\n#[global_allocator]\nstatic GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;\n\n#[derive(Parser)]\nstruct Args {\n    /// Disable terminal support.\n    #[clap(long)]\n    no_term: bool,\n    /// Write the report to an output path in json format.\n    #[clap(long)]\n    output_path: Option<PathBuf>,\n\n    /// The number of rounds to run.\n    #[clap(long, default_value_t = 10)]\n    rounds: usize,\n}\n\nfn dur_as_millis_f64(dur: Duration) -> f64 {\n    i32::try_from(dur.as_micros()).map(f64::from).unwrap() / 1000.0\n}\n\nfn bench_baseline() -> Duration {\n    fn fib(n: u32) -> u32 {\n        if n <= 1 {\n            1\n        } else {\n            fib(n - 1) + fib(n - 2)\n        }\n    }\n\n    let start_time = Instant::now();\n    fib(40);\n    start_time.elapsed()\n}\n\nasync fn bench_hello_world() -> Duration {\n    static TOTAL: usize = 1_000_000;\n\n    #[function_component]\n    fn App() -> Html {\n        html! {<div>{\"Hello, World!\"}</div>}\n    }\n\n    let start_time = Instant::now();\n\n    for _ in 0..TOTAL {\n        yew::LocalServerRenderer::<App>::new().render().await;\n    }\n\n    start_time.elapsed()\n}\n\nasync fn bench_router_app() -> Duration {\n    static TOTAL: usize = 100_000;\n\n    let start_time = Instant::now();\n\n    for _ in 0..TOTAL {\n        yew::LocalServerRenderer::<ServerApp>::with_props(ServerAppProps {\n            url: \"/\".into(),\n            queries: HashMap::new(),\n        })\n        .render()\n        .await;\n    }\n\n    start_time.elapsed()\n}\n\nasync fn bench_many_providers() -> Duration {\n    static TOTAL: usize = 250_000;\n\n    #[derive(Properties, PartialEq, Clone)]\n    struct ProviderProps {\n        children: Html,\n    }\n\n    #[function_component]\n    fn Provider(props: &ProviderProps) -> Html {\n        let ProviderProps { children } = props.clone();\n\n        children\n    }\n\n    #[function_component]\n    fn App() -> Html {\n        // Let's make 10 providers.\n        html! {\n            <Provider>\n                <Provider>\n                    <Provider>\n                        <Provider>\n                            <Provider>\n                                <Provider>\n                                    <Provider>\n                                        <Provider>\n                                            <Provider>\n                                                <Provider>{\"Hello, World!\"}</Provider>\n                                            </Provider>\n                                        </Provider>\n                                    </Provider>\n                                </Provider>\n                            </Provider>\n                        </Provider>\n                    </Provider>\n                </Provider>\n            </Provider>\n        }\n    }\n\n    let start_time = Instant::now();\n\n    for _ in 0..TOTAL {\n        yew::LocalServerRenderer::<App>::new().render().await;\n    }\n\n    start_time.elapsed()\n}\n\nasync fn bench_concurrent_task() -> Duration {\n    static TOTAL: usize = 100;\n\n    let start_time = Instant::now();\n\n    #[function_component]\n    fn Comp() -> HtmlResult {\n        let _state = use_prepared_state!((), async move |_| -> usize {\n            sleep(Duration::from_secs(1)).await;\n            42\n        })?;\n\n        Ok(Html::default())\n    }\n\n    #[function_component]\n    fn Parent() -> Html {\n        html! {\n            <>\n                <Comp />\n                <Comp />\n                <Comp />\n                <Comp />\n            </>\n        }\n    }\n\n    #[function_component]\n    fn App() -> Html {\n        html! {\n            <Suspense fallback={Html::default()}>\n                <Parent />\n                <Comp />\n                <Comp />\n                <Comp />\n                <Comp />\n            </Suspense>\n        }\n    }\n\n    let mut tasks = Vec::new();\n\n    for _ in 0..TOTAL {\n        tasks.push(spawn_local(async {\n            yew::LocalServerRenderer::<App>::new().render().await;\n        }));\n    }\n\n    for task in tasks {\n        task.await.expect(\"failed to finish task\");\n    }\n\n    start_time.elapsed()\n}\n\n#[derive(Debug, Tabled, Serialize, Deserialize)]\nstruct Statistics {\n    #[tabled(rename = \"Benchmark\")]\n    name: String,\n    #[tabled(rename = \"Round\")]\n    round: String,\n    #[tabled(rename = \"Min (ms)\")]\n    min: String,\n    #[tabled(rename = \"Max (ms)\")]\n    max: String,\n    #[tabled(rename = \"Mean (ms)\")]\n    mean: String,\n    #[tabled(rename = \"Standard Deviation\")]\n    std_dev: String,\n}\n\nimpl Statistics {\n    fn from_results<S>(name: S, round: usize, mut results: Vec<Duration>) -> Self\n    where\n        S: Into<String>,\n    {\n        let name = name.into();\n\n        results.sort();\n\n        let var: Variance = results.iter().cloned().map(dur_as_millis_f64).collect();\n\n        Self {\n            name,\n            round: round.to_string(),\n            min: format!(\"{:.3}\", dur_as_millis_f64(results[0])),\n            max: format!(\n                \"{:.3}\",\n                dur_as_millis_f64(*results.last().expect(\"array is empty?\"))\n            ),\n            std_dev: format!(\"{:.3}\", var.sample_variance().sqrt()),\n            mean: format!(\"{:.3}\", var.mean()),\n        }\n    }\n}\n\nfn create_progress(tests: usize, rounds: usize) -> ProgressBar {\n    let bar = ProgressBar::new((tests * rounds) as u64);\n    // Progress Bar needs to be updated in a different thread.\n    {\n        let bar = bar.downgrade();\n        std::thread::spawn(move || {\n            while let Some(bar) = bar.upgrade() {\n                bar.tick();\n                std::thread::sleep(Duration::from_millis(100));\n            }\n        });\n    }\n\n    bar.set_style(\n        ProgressStyle::default_bar()\n            .template(&format!(\n                \"{{spinner:.green}} {{prefix}} [{{elapsed_precise}}] [{{bar:40.cyan/blue}}] round \\\n                 {{msg}}/{rounds}\",\n            ))\n            .expect(\"failed to parse template\")\n            // .tick_chars(\"-\\\\|/\")\n            .progress_chars(\"=>-\"),\n    );\n\n    bar\n}\n\n#[tokio::main]\nasync fn main() {\n    let local_set = LocalSet::new();\n\n    let args = Args::parse();\n\n    // Tests in each round.\n    static TESTS: usize = 5;\n\n    let mut baseline_results = Vec::with_capacity(args.rounds);\n    let mut hello_world_results = Vec::with_capacity(args.rounds);\n    let mut function_router_results = Vec::with_capacity(args.rounds);\n    let mut concurrent_tasks_results = Vec::with_capacity(args.rounds);\n    let mut many_provider_results = Vec::with_capacity(args.rounds);\n\n    let bar = (!args.no_term).then(|| create_progress(TESTS, args.rounds));\n\n    local_set\n        .run_until(async {\n            for i in 0..=args.rounds {\n                if let Some(ref bar) = bar {\n                    bar.set_message(i.to_string());\n                    if i == 0 {\n                        bar.set_prefix(\"Warming up\");\n                    } else {\n                        bar.set_prefix(\"Running   \");\n                    }\n                }\n\n                let dur = bench_baseline();\n                if i > 0 {\n                    baseline_results.push(dur);\n                    if let Some(ref bar) = bar {\n                        bar.inc(1);\n                    }\n                }\n\n                let dur = bench_hello_world().await;\n                if i > 0 {\n                    hello_world_results.push(dur);\n                    if let Some(ref bar) = bar {\n                        bar.inc(1);\n                    }\n                }\n\n                let dur = bench_router_app().await;\n                if i > 0 {\n                    function_router_results.push(dur);\n                    if let Some(ref bar) = bar {\n                        bar.inc(1);\n                    }\n                }\n\n                let dur = bench_concurrent_task().await;\n                if i > 0 {\n                    concurrent_tasks_results.push(dur);\n                    if let Some(ref bar) = bar {\n                        bar.inc(1);\n                    }\n                }\n\n                let dur = bench_many_providers().await;\n                if i > 0 {\n                    many_provider_results.push(dur);\n                    if let Some(ref bar) = bar {\n                        bar.inc(1);\n                    }\n                }\n            }\n        })\n        .await;\n\n    if let Some(ref bar) = bar {\n        bar.finish_and_clear();\n    }\n    drop(bar);\n\n    let output = [\n        Statistics::from_results(\"Baseline\", args.rounds, baseline_results),\n        Statistics::from_results(\"Hello World\", args.rounds, hello_world_results),\n        Statistics::from_results(\"Function Router\", args.rounds, function_router_results),\n        Statistics::from_results(\"Concurrent Task\", args.rounds, concurrent_tasks_results),\n        Statistics::from_results(\"Many Providers\", args.rounds, many_provider_results),\n    ];\n\n    println!(\"{}\", Table::new(&output).with(Style::rounded()));\n\n    if let Some(ref p) = args.output_path {\n        let mut f = File::create(p).expect(\"failed to write output.\");\n        serde_json::to_writer_pretty(&mut f, &output).expect(\"failed to write output.\");\n\n        println!();\n        println!(\"Result has been written to: {}\", p.display());\n    }\n}\n"
  },
  {
    "path": "tools/benchmark-struct/.gitignore",
    "content": "node_modules\n/target\n/bundled-dist\n"
  },
  {
    "path": "tools/benchmark-struct/Cargo.toml",
    "content": "[package]\nname = \"js-framework-benchmark-yew\"\nversion = \"1.0.0\"\nauthors = [\"Isamu Mogi <isamu@leafytree.jp>\"]\nedition = \"2021\"\n\n[lib]\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nrand = { workspace = true, features = [\"small_rng\"] }\ngetrandom = { workspace = true }\nwasm-bindgen.workspace = true\nweb-sys = { workspace = true, features = [\"Window\"]}\nyew = { version = \"0.23.0\", features = [\"csr\"], path = \"../../packages/yew\" }\n\n[package.metadata.wasm-pack.profile.release]\nwasm-opt = ['-O4']\n"
  },
  {
    "path": "tools/benchmark-struct/Makefile.toml",
    "content": "# Extends the root Makefile.toml\n\n[tasks.doc-test]\ncommand = \"echo\"\nargs = [\"No doctests run for benchmark-struct\"]"
  },
  {
    "path": "tools/benchmark-struct/README.md",
    "content": "Copied from https://github.com/krausest/js-framework-benchmark\n\nIt should ideally stay/be updated to always match what is on https://github.com/krausest/js-framework-benchmark\nExcept the fixes required to tun using unreleased yew version.\n\nIf you want to improve benchmarks, consider first opening a PR to https://github.com/krausest/js-framework-benchmark and only then sync this package with it.\n"
  },
  {
    "path": "tools/benchmark-struct/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Yew</title>\n    <link href=\"/css/currentStyle.css\" rel=\"stylesheet\"/>\n    <base href=\"bundled-dist/\"></base>\n  </head>\n  <body>\n    <div id='main'></div>\n    <script type=\"module\">\n      import init from './js-framework-benchmark-yew.js';\n      init('./js-framework-benchmark-yew_bg.wasm');\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tools/benchmark-struct/package.json",
    "content": "{\n  \"name\": \"js-framework-benchmark-keyed-yew\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Benchmark for Yew\",\n  \"license\": \"ISC\",\n  \"js-framework-benchmark\": {\n    \"frameworkVersion\": \"latest\",\n    \"frameworkHomeURL\": \"https://yew.rs/\",\n    \"issues\": [\n      1139\n    ]\n  },\n  \"scripts\": {\n    \"build-prod\": \"echo This is a no-op. && echo Due to heavy dependencies, the generated javascript is already provided. && echo If you really want to rebuild from source use: && echo npm run build-prod-force\",\n    \"build-prod-force\": \"rustup target add wasm32-unknown-unknown && cargo install wasm-pack && npx build-prod-without-tools-install\",\n    \"build-prod-without-tools-install\": \"rimraf bundled-dist && wasm-pack build --release --target web --no-typescript --out-name js-framework-benchmark-yew --out-dir bundled-dist && cpr index.html bundled-dist/index.html && (cd bundled-dist && rimraf .gitignore README.md package.json)\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/krausest/js-framework-benchmark.git\"\n  },\n  \"devDependencies\": {\n    \"cpr\": \"^3.0.1\",\n    \"rimraf\": \"^2.6.3\"\n  },\n  \"dependencies\": {\n    \"js-framework-benchmark-keyed-yew\": \"file:\"\n  }\n}\n"
  },
  {
    "path": "tools/benchmark-struct/src/lib.rs",
    "content": "use std::cmp::min;\n\nuse rand::prelude::*;\nuse wasm_bindgen::prelude::*;\nuse web_sys::window;\nuse yew::prelude::*;\n\nstatic ADJECTIVES: &[&str] = &[\n    \"pretty\",\n    \"large\",\n    \"big\",\n    \"small\",\n    \"tall\",\n    \"short\",\n    \"long\",\n    \"handsome\",\n    \"plain\",\n    \"quaint\",\n    \"clean\",\n    \"elegant\",\n    \"easy\",\n    \"angry\",\n    \"crazy\",\n    \"helpful\",\n    \"mushy\",\n    \"odd\",\n    \"unsightly\",\n    \"adorable\",\n    \"important\",\n    \"inexpensive\",\n    \"cheap\",\n    \"expensive\",\n    \"fancy\",\n];\n\nstatic COLOURS: &[&str] = &[\n    \"red\", \"yellow\", \"blue\", \"green\", \"pink\", \"brown\", \"purple\", \"brown\", \"white\", \"black\",\n    \"orange\",\n];\n\nstatic NOUNS: &[&str] = &[\n    \"table\", \"chair\", \"house\", \"bbq\", \"desk\", \"car\", \"pony\", \"cookie\", \"sandwich\", \"burger\",\n    \"pizza\", \"mouse\", \"keyboard\",\n];\n\n#[derive(Clone, PartialEq)]\nstruct RowData {\n    id: usize,\n    label: String,\n}\n\nimpl RowData {\n    fn new(id: usize, rng: &mut SmallRng) -> Self {\n        let adjective = *ADJECTIVES.choose(rng).unwrap();\n        let colour = *COLOURS.choose(rng).unwrap();\n        let noun = *NOUNS.choose(rng).unwrap();\n\n        let label = [adjective, colour, noun].join(\" \");\n\n        Self { id, label }\n    }\n}\n\nstruct App {\n    rows: Vec<RowData>,\n    next_id: usize,\n    selected_id: Option<usize>,\n    rng: SmallRng,\n    on_select: Callback<usize>,\n    on_remove: Callback<usize>,\n}\n\nenum Msg {\n    Run(usize),\n    Add(usize),\n    Update(usize),\n    Clear,\n    Swap,\n    Remove(usize),\n    Select(usize),\n}\n\nimpl Component for App {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        App {\n            rows: Vec::new(),\n            next_id: 1,\n            selected_id: None,\n            rng: SmallRng::from_os_rng(),\n            on_select: ctx.link().callback(Msg::Select),\n            on_remove: ctx.link().callback(Msg::Remove),\n        }\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::Run(amount) => {\n                let rng = &mut self.rng;\n                let next_id = self.next_id;\n                let update_amount = min(amount, self.rows.len());\n                for index in 0..update_amount {\n                    self.rows[index] = RowData::new(next_id + index, rng);\n                }\n                self.rows.extend(\n                    (update_amount..amount).map(|index| RowData::new(next_id + index, rng)),\n                );\n                self.next_id += amount;\n            }\n            Msg::Add(amount) => {\n                let rng = &mut self.rng;\n                let next_id = self.next_id;\n                self.rows\n                    .extend((0..amount).map(|index| RowData::new(next_id + index, rng)));\n                self.next_id += amount;\n            }\n            Msg::Update(step) => {\n                for index in (0..self.rows.len()).step_by(step) {\n                    self.rows[index].label += \" !!!\";\n                }\n            }\n            Msg::Clear => {\n                self.rows.clear();\n            }\n            Msg::Swap => {\n                if self.rows.len() > 998 {\n                    self.rows.swap(1, 998);\n                }\n            }\n            Msg::Remove(id) => {\n                if let Some(index) = self.rows.iter().position(|row| row.id == id) {\n                    self.rows.remove(index);\n                }\n            }\n            Msg::Select(id) => {\n                self.selected_id = Some(id);\n            }\n        }\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let rows: Html = self\n            .rows\n            .iter()\n            .map(|row| {\n                html! {\n                    <Row\n                        key={row.id}\n                        data={row.clone()}\n                        selected={self.selected_id == Some(row.id)}\n                        on_select={self.on_select.clone()}\n                        on_remove={self.on_remove.clone()}\n                    />\n                }\n            })\n            .collect();\n\n        html! {\n            <div class=\"container\">\n                <Jumbotron\n                    on_run={ctx.link().callback(Msg::Run)}\n                    on_add={ctx.link().callback(Msg::Add)}\n                    on_update={ctx.link().callback(Msg::Update)}\n                    on_clear={ctx.link().callback(|_| Msg::Clear)}\n                    on_swap={ctx.link().callback(|_| Msg::Swap)}\n                />\n                <table class=\"table table-hover table-striped test-data\">\n                    <tbody id=\"tbody\">\n                        { rows }\n                    </tbody>\n                </table>\n                <span class=\"preloadicon glyphicon glyphicon-remove\" aria-hidden=\"true\"></span>\n            </div>\n        }\n    }\n}\n\n#[derive(Properties, Clone, PartialEq)]\npub struct JumbotronProps {\n    pub on_run: Callback<usize>,\n    pub on_add: Callback<usize>,\n    pub on_update: Callback<usize>,\n    pub on_clear: Callback<()>,\n    pub on_swap: Callback<()>,\n}\n\npub struct Jumbotron {}\n\nimpl Component for Jumbotron {\n    type Message = ();\n    type Properties = JumbotronProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {}\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"jumbotron\">\n                <div class=\"row\">\n                    <div class=\"col-md-6\">\n                        <h1>{ \"Yew\" }</h1>\n                    </div>\n                    <div class=\"col-md-6\">\n                        <div class=\"row\">\n                            <div class=\"col-sm-6 smallpad\">\n                                <button type=\"button\" id=\"run\" class=\"btn btn-primary btn-block\" onclick={ctx.props().on_run.reform(|_| 1_000)}>{ \"Create 1,000 rows\" }</button>\n                            </div>\n                            <div class=\"col-sm-6 smallpad\">\n                                <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={ctx.props().on_run.reform(|_| 10_000)} id=\"runlots\">{ \"Create 10,000 rows\" }</button>\n                            </div>\n                            <div class=\"col-sm-6 smallpad\">\n                                <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={ctx.props().on_add.reform(|_| 1_000)} id=\"add\">{ \"Append 1,000 rows\" }</button>\n                            </div>\n                            <div class=\"col-sm-6 smallpad\">\n                                <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={ctx.props().on_update.reform(|_| 10)} id=\"update\">{ \"Update every 10th row\" }</button>\n                            </div>\n                            <div class=\"col-sm-6 smallpad\">\n                                <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={ctx.props().on_clear.reform(|_| ())} id=\"clear\">{ \"Clear\" }</button>\n                            </div>\n                            <div class=\"col-sm-6 smallpad\">\n                                <button type=\"button\" class=\"btn btn-primary btn-block\" onclick={ctx.props().on_swap.reform(|_| ())} id=\"swaprows\">{ \"Swap Rows\" }</button>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        }\n    }\n}\n\n#[derive(Properties, Clone, PartialEq)]\nstruct RowProps {\n    on_select: Callback<usize>,\n    on_remove: Callback<usize>,\n    selected: bool,\n    data: RowData,\n}\n\nstruct Row {\n    on_select: Callback<MouseEvent>,\n    on_remove: Callback<MouseEvent>,\n}\n\nimpl Component for Row {\n    type Message = ();\n    type Properties = RowProps;\n\n    fn create(ctx: &Context<Self>) -> Self {\n        let id = ctx.props().data.id;\n        Self {\n            on_select: ctx.props().on_select.reform(move |_| id),\n            on_remove: ctx.props().on_remove.reform(move |_| id),\n        }\n    }\n\n    fn changed(&mut self, ctx: &Context<Self>, _: &Self::Properties) -> bool {\n        let id = ctx.props().data.id;\n        self.on_select = ctx.props().on_select.reform(move |_| id);\n        self.on_remove = ctx.props().on_remove.reform(move |_| id);\n        true\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <tr class={if ctx.props().selected { \"danger\" } else  { \"\" }}>\n                <td class=\"col-md-1\">{ ctx.props().data.id }</td>\n                <td class=\"col-md-4\" onclick={self.on_select.clone()}>\n                    <a class=\"lbl\">{ ctx.props().data.label.clone() }</a>\n                </td>\n                <td class=\"col-md-1\">\n                    <a class=\"remove\" onclick={self.on_remove.clone()}>\n                        <span class=\"glyphicon glyphicon-remove remove\" aria-hidden=\"true\"></span>\n                    </a>\n                </td>\n                <td class=\"col-md-6\"></td>\n            </tr>\n        }\n    }\n}\n\n#[wasm_bindgen(start)]\npub fn start() {\n    let document = window().unwrap().document().unwrap();\n    let mount_el = document.query_selector(\"#main\").unwrap().unwrap();\n    yew::Renderer::<App>::with_root(mount_el).render();\n}\n"
  },
  {
    "path": "tools/build-examples/Cargo.toml",
    "content": "[package]\nname = \"build-examples\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\n\n[dependencies]\nreqwest = { workspace = true, features = [\"blocking\", \"json\"] }\nregex = \"1.12.3\"\ntoml = \"1.0.6\"\nserde = { workspace = true, features = [\"derive\"] }\n"
  },
  {
    "path": "tools/build-examples/src/bin/update-wasm-opt.rs",
    "content": "use std::fs;\nuse std::path::{Path, PathBuf};\nuse std::process::ExitCode;\n\nuse build_examples::{get_latest_wasm_opt_version, is_wasm_opt_outdated, NO_TRUNK_EXAMPLES};\nuse regex::Regex;\n\nfn main() -> ExitCode {\n    // Must be run from root of the repo\n    let examples_dir = Path::new(\"examples\");\n    if !examples_dir.exists() {\n        eprintln!(\n            \"examples directory not found. Make sure you're running from the root of the repo.\"\n        );\n        return ExitCode::from(1);\n    }\n\n    let latest_wasm_opt = get_latest_wasm_opt_version();\n    let mut outdated_example_paths = Vec::new();\n    let mut outdated_examples = Vec::new();\n\n    // Get all entries in the examples directory\n    let entries = fs::read_dir(examples_dir).expect(\"Failed to read examples directory\");\n\n    for entry in entries {\n        let entry = entry.expect(\"Failed to read directory entry\");\n        let path = entry.path();\n\n        // Skip if not a directory\n        if !path.is_dir() {\n            continue;\n        }\n\n        // Skip hidden directories (e.g., .cargo)\n        let file_name = entry.file_name();\n        if file_name.to_string_lossy().starts_with('.') {\n            continue;\n        }\n\n        let example = path\n            .file_name()\n            .expect(\"Failed to get directory name\")\n            .to_string_lossy()\n            .to_string();\n\n        // Skip ssr examples as they don't need trunk\n        if NO_TRUNK_EXAMPLES.contains(&example.as_str()) {\n            continue;\n        }\n\n        // Check Trunk.toml for wasm_opt version and collect outdated examples\n        if is_wasm_opt_outdated(&path, &latest_wasm_opt) {\n            outdated_examples.push(example);\n            outdated_example_paths.push(path);\n        }\n    }\n\n    if outdated_examples.is_empty() {\n        println!(\"All examples are up-to-date with the latest wasm_opt version: {latest_wasm_opt}\");\n        return ExitCode::from(0);\n    }\n\n    println!(\n        \"Found {} examples with outdated or missing wasm_opt configuration:\",\n        outdated_examples.len()\n    );\n    for example in &outdated_examples {\n        println!(\"  - {example}\");\n    }\n    println!(\"Latest wasm_opt version is: {latest_wasm_opt}\");\n    println!(\"Updating all examples...\");\n\n    let updated_count = update_all_examples(&outdated_example_paths, &latest_wasm_opt);\n    println!(\"Updated {updated_count} example configurations to use {latest_wasm_opt}\");\n\n    ExitCode::from(0)\n}\n\npub fn update_all_examples(outdated_paths: &[PathBuf], latest_version: &str) -> usize {\n    let mut updated_count = 0;\n\n    let re = Regex::new(r#\"(?m)^\\[tools\\]\\s*\\nwasm_opt\\s*=\\s*\"(version_\\d+)\"\"#).unwrap();\n    for path in outdated_paths {\n        let trunk_toml_path = path.join(\"Trunk.toml\");\n\n        let content = fs::read_to_string(&trunk_toml_path).unwrap_or_default();\n\n        let updated_content = if re.is_match(&content) {\n            // Replace existing wasm_opt version\n            re.replace(&content, |_: &regex::Captures| {\n                format!(\n                    r#\"[tools]\nwasm_opt = \"{latest_version}\"\"#\n                )\n            })\n            .to_string()\n        } else {\n            // Add wasm_opt configuration\n            if content.is_empty() {\n                format!(\n                    r#\"[tools]\nwasm_opt = \"{latest_version}\"\"#\n                )\n            } else {\n                format!(\n                    \"{}\\n\\n[tools]\\nwasm_opt = \\\"{}\\\"\",\n                    content.trim(),\n                    latest_version\n                )\n            }\n        };\n\n        if let Err(e) = fs::write(&trunk_toml_path, updated_content) {\n            println!(\"Failed to update {}: {}\", trunk_toml_path.display(), e);\n        } else {\n            updated_count += 1;\n        }\n    }\n\n    updated_count\n}\n"
  },
  {
    "path": "tools/build-examples/src/lib.rs",
    "content": "use std::path::Path;\nuse std::{env, fs};\n\nuse serde::Deserialize;\nuse toml::Table;\n\n/// Examples that don't use Trunk for building\npub const NO_TRUNK_EXAMPLES: [&str; 3] = [\"simple_ssr\", \"ssr_router\", \"wasi_ssr_module\"];\n\n#[derive(Deserialize)]\nstruct GitHubRelease {\n    tag_name: String,\n}\n\npub fn get_latest_wasm_opt_version() -> String {\n    if let Ok(version) = env::var(\"LATEST_WASM_OPT_VERSION\") {\n        if !version.is_empty() {\n            return version;\n        }\n    }\n\n    get_latest_wasm_opt_version_from_api()\n}\n\nfn get_latest_wasm_opt_version_from_api() -> String {\n    let url = \"https://api.github.com/repos/WebAssembly/binaryen/releases/latest\";\n    let client = reqwest::blocking::Client::new();\n\n    // github api requires a user agent\n    // https://docs.github.com/en/rest/using-the-rest-api/troubleshooting-the-rest-api?apiVersion=2022-11-28#user-agent-required\n    let req_builder = client.get(url).header(\"User-Agent\", \"yew-wasm-opt-checker\");\n\n    // Send the request\n    let res = req_builder\n        .send()\n        .expect(\"Failed to send request to GitHub API\");\n\n    if !res.status().is_success() {\n        // Get more details about the error\n        let status = res.status();\n        let error_text = res\n            .text()\n            .unwrap_or_else(|_| \"Could not read error response\".to_string());\n\n        panic!(\"GitHub API request failed with status: {status}. Details: {error_text}\");\n    }\n\n    let release: GitHubRelease = res.json().expect(\"Failed to parse GitHub API response\");\n    release.tag_name\n}\n\npub fn is_wasm_opt_outdated(path: &Path, latest_version: &str) -> bool {\n    let trunk_toml_path = path.join(\"Trunk.toml\");\n\n    if !trunk_toml_path.exists() {\n        return true;\n    }\n\n    let content = match fs::read_to_string(&trunk_toml_path) {\n        Ok(content) => content,\n        Err(_) => return true,\n    };\n\n    // Check if wasm_opt is configured and up-to-date\n    let table: Table = toml::from_str(&content).unwrap();\n    let tools = table.get(\"tools\").unwrap().as_table().unwrap();\n    let wasm_opt = tools.get(\"wasm_opt\").unwrap().as_str().unwrap();\n    wasm_opt != latest_version\n}\n"
  },
  {
    "path": "tools/build-examples/src/main.rs",
    "content": "use std::path::Path;\nuse std::process::{Command, ExitCode};\nuse std::{env, fs};\n\nuse build_examples::{get_latest_wasm_opt_version, is_wasm_opt_outdated, NO_TRUNK_EXAMPLES};\n\nfn main() -> ExitCode {\n    // Must be run from root of the repo:\n    // yew $ cargo r -p build-examples -b build-examples\n    let output_dir = env::current_dir().expect(\"Failed to get current directory\");\n    let output_dir = output_dir.join(\"dist\");\n\n    fs::create_dir_all(&output_dir).expect(\"Failed to create output directory\");\n\n    let examples_dir = Path::new(\"examples\");\n    if !examples_dir.exists() {\n        eprintln!(\n            \"examples directory not found. Make sure you're running from the root of the repo.\"\n        );\n        return ExitCode::from(1);\n    }\n\n    let mut failure = false;\n    let latest_wasm_opt = get_latest_wasm_opt_version();\n    let mut outdated_examples = Vec::new();\n    let mut outdated_example_paths = Vec::new();\n\n    // Get all entries in the examples directory\n    let entries = fs::read_dir(examples_dir).expect(\"Failed to read examples directory\");\n\n    for entry in entries {\n        let entry = entry.expect(\"Failed to read directory entry\");\n        let path = entry.path();\n\n        // Skip if not a directory\n        if should_skip_path(&path) {\n            continue;\n        }\n\n        let example = path\n            .file_name()\n            .expect(\"Failed to get directory name\")\n            .to_string_lossy()\n            .to_string();\n\n        // Skip ssr examples as they don't need trunk\n        if NO_TRUNK_EXAMPLES.contains(&example.as_str()) {\n            continue;\n        }\n\n        // Check Trunk.toml for wasm_opt version and collect outdated examples\n        if is_wasm_opt_outdated(&path, &latest_wasm_opt) {\n            outdated_examples.push(example.clone());\n            outdated_example_paths.push(path.clone());\n        }\n\n        println!(\"::group::Building {example}\");\n\n        let sample_success = build_example(&path, &output_dir, &example);\n\n        println!(\"::endgroup::\");\n        if !sample_success {\n            eprintln!(\"::error ::{example}  failed to build\");\n            failure = true;\n        }\n    }\n\n    // Emit warning if any examples have outdated wasm_opt\n    if !outdated_examples.is_empty() {\n        println!(\n            \"::warning ::{} example crates do not have up-to-date wasm_opt: {}\",\n            outdated_examples.len(),\n            outdated_examples.join(\", \")\n        );\n    }\n\n    if failure {\n        ExitCode::from(1)\n    } else {\n        ExitCode::from(0)\n    }\n}\n\nfn should_skip_path(path: &Path) -> bool {\n    !path.is_dir() || !path.join(\"Cargo.toml\").exists()\n}\n\nfn build_example(path: &Path, output_dir: &Path, example: &str) -> bool {\n    let public_url_prefix = env::var(\"PUBLIC_URL_PREFIX\").unwrap_or_default();\n\n    let dist_dir = output_dir.join(example);\n\n    // Run trunk build command\n    let status = Command::new(\"trunk\")\n        .current_dir(path)\n        .arg(\"build\")\n        .arg(\"--release\")\n        .arg(\"--dist\")\n        .arg(&dist_dir)\n        .arg(\"--public-url\")\n        .arg(format!(\"{public_url_prefix}/{example}\"))\n        .arg(\"--no-sri\")\n        .status();\n\n    match status {\n        Ok(status) if status.success() => {\n            // Check for undefined symbols (imports from 'env')\n            let js_files = match fs::read_dir(&dist_dir) {\n                Ok(entries) => entries\n                    .filter_map(Result::ok)\n                    .filter(|e| e.path().extension().is_some_and(|ext| ext == \"js\"))\n                    .collect::<Vec<_>>(),\n                Err(_) => return false,\n            };\n\n            for js_file in js_files {\n                let content = match fs::read_to_string(js_file.path()) {\n                    Ok(content) => content,\n                    Err(_) => return false,\n                };\n\n                if content.contains(\"from 'env'\") {\n                    return false;\n                }\n            }\n\n            true\n        }\n        _ => false,\n    }\n}\n"
  },
  {
    "path": "tools/changelog/Cargo.toml",
    "content": "[package]\nname = \"changelog\"\nversion = \"0.1.0\"\nauthors = [\"Cecile Tonglet <cecile.tonglet@cecton.com>\"]\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nanyhow.workspace = true\nchrono = \"0.4\"\ngit2 = \"0.20\"\nregex = \"1\"\nreqwest = { workspace = true, features = [\"blocking\", \"json\"] }\nserde = { workspace = true, features = [\"derive\"] }\nstrum = { workspace = true, features = [\"derive\"] }\nclap = { workspace = true }\nsemver = \"1.0\"\n"
  },
  {
    "path": "tools/changelog/Makefile.toml",
    "content": "# Extends the root Makefile.toml\n\n[tasks.doc-test]\ncommand = \"echo\"\nargs = [\"No doctests run for changelog\"]"
  },
  {
    "path": "tools/changelog/src/cli.rs",
    "content": "use anyhow::{bail, Result};\nuse clap::Parser;\nuse semver::Version;\n\nuse crate::create_log_lines::create_log_lines;\nuse crate::get_latest_version::get_latest_version;\nuse crate::new_version_level::NewVersionLevel;\nuse crate::stdout_tag_description_changelog::stdout_tag_description_changelog;\nuse crate::write_changelog_file::write_changelog;\nuse crate::write_log_lines::write_log_lines;\nuse crate::write_version_changelog::write_changelog_file;\nuse crate::yew_package::YewPackage;\n\n#[derive(Parser)]\npub struct Cli {\n    /// package to generate changelog for\n    pub package: YewPackage,\n\n    /// package to generate changelog for\n    pub new_version_level: NewVersionLevel,\n\n    /// From ref. (ex. commit hash or for tags \"refs/tags/yew-v0.19.3\") overrides version level arg\n    pub from: Option<String>,\n\n    /// To commit. (ex. commit hash or for tags \"refs/tags/yew-v0.19.3\")\n    #[clap(short = 'r', long, default_value = \"HEAD\")]\n    pub to: String,\n\n    /// Path to changelog file\n    #[clap(short = 'f', long, default_value = \"../CHANGELOG.md\")]\n    pub changelog_path: String,\n\n    /// Skip writing changelog file\n    #[clap(short, long)]\n    pub skip_file_write: bool,\n\n    /// Skip getting the next version\n    #[clap(short = 'b', long)]\n    pub skip_get_bump_version: bool,\n\n    /// Github token\n    #[clap(short = 't', long)]\n    pub token: Option<String>,\n}\n\nimpl Cli {\n    pub fn run(self) -> Result<()> {\n        let Cli {\n            package,\n            from,\n            to,\n            changelog_path,\n            skip_file_write,\n            new_version_level,\n            skip_get_bump_version,\n            token,\n        } = self;\n        let package_labels = package.as_labels();\n\n        // set up versions and from ref\n        let (from_ref, next_version) = if skip_get_bump_version {\n            let from_ref = match from {\n                Some(some) => some,\n                None => bail!(\"from required when skip_get_bump_version is true\"),\n            };\n            let version = Version::parse(\"0.0.0\")?;\n            (from_ref, version)\n        } else {\n            let latest_version = get_latest_version(&package)?;\n\n            let next_version = new_version_level.bump(latest_version.clone());\n\n            let from_ref = match from {\n                Some(some) => some,\n                None => format!(\"refs/tags/{package}-v{latest_version}\"),\n            };\n            (from_ref, next_version)\n        };\n\n        // walk over each commit find text, user, issue\n        let log_lines = create_log_lines(from_ref, to, package_labels, token)?;\n\n        // categorize logs\n        let (breaking_changes, filtered_log_lines): (Vec<_>, Vec<_>) = log_lines\n            .into_iter()\n            .partition(|log_line| log_line.is_breaking_change);\n\n        let (fixes, features): (Vec<_>, Vec<_>) =\n            filtered_log_lines\n                .into_iter()\n                .partition(|filtered_log_line| {\n                    filtered_log_line.message.to_lowercase().contains(\"fix\")\n                });\n\n        // create displayable log lines\n        let fixes_logs = write_log_lines(fixes)?;\n        let features_logs = write_log_lines(features)?;\n        let breaking_changes_logs = write_log_lines(breaking_changes)?;\n\n        if !skip_file_write {\n            // create version changelog\n            let version_changelog = write_changelog_file(\n                &fixes_logs,\n                &features_logs,\n                &breaking_changes_logs,\n                package,\n                next_version,\n            )?;\n\n            // write changelog\n            write_changelog(&changelog_path, &version_changelog)?;\n        }\n\n        // stdout changelog meant for tag description\n        stdout_tag_description_changelog(&fixes_logs, &features_logs, &breaking_changes_logs)?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "tools/changelog/src/create_log_line.rs",
    "content": "use std::sync::{LazyLock, Mutex};\n\nuse anyhow::{anyhow, Context, Result};\nuse git2::{Error, Oid, Repository};\nuse regex::Regex;\n\nuse crate::github_issue_labels_fetcher::GitHubIssueLabelsFetcher;\nuse crate::github_user_fetcher::GitHubUsersFetcher;\nuse crate::log_line::LogLine;\n\nstatic REGEX_FOR_ISSUE_ID_CAPTURE: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"\\s*\\(#(\\d+)\\)\").unwrap());\nstatic GITHUB_ISSUE_LABELS_FETCHER: LazyLock<Mutex<GitHubIssueLabelsFetcher>> =\n    LazyLock::new(Default::default);\n\npub fn create_log_line(\n    repo: &Repository,\n    package_labels: &'static [&'static str],\n    oid: Result<Oid, Error>,\n    token: Option<String>,\n    user_fetcher: &mut GitHubUsersFetcher,\n) -> Result<Option<LogLine>> {\n    println!(\"Commit oid: {oid:?}\");\n    let oid = oid?;\n    let commit = repo.find_commit(oid)?;\n    let commit_first_line = commit\n        .message()\n        .context(\"Invalid UTF-8 in commit message\")?\n        .lines()\n        .next()\n        .context(\"Missing commit message\")?\n        .to_string();\n    let author = commit.author();\n    let author_name = author.name().unwrap_or(\"Unknown\");\n    let author_id = user_fetcher\n        .fetch_user_by_commit_author(author_name, commit.id().to_string(), token.clone())\n        .context(\"Missing author's GitHub ID\")?;\n    let email = author.email().context(\"Missing author's email\")?;\n\n    if email.contains(\"dependabot\") {\n        println!(\"email contains dependabot\");\n        return Ok(None);\n    }\n\n    if email.contains(\"github-action\") {\n        println!(\"email contains github-action\");\n        return Ok(None);\n    }\n\n    let mb_captures = REGEX_FOR_ISSUE_ID_CAPTURE\n        .captures_iter(&commit_first_line)\n        .last();\n\n    let captures = match mb_captures {\n        Some(some) => some,\n        None => {\n            eprintln!(\"Missing issue for commit: {oid}\");\n            return Ok(None);\n        }\n    };\n\n    let match_to_be_stripped = captures.get(0).ok_or_else(|| {\n        anyhow!(\"Failed to capture first group - issue part of the message like \\\" (#2263)\\\"\")\n    })?;\n    let mut message = commit_first_line.clone();\n    message.replace_range(match_to_be_stripped.range(), \"\");\n\n    let issue_id = captures\n        .get(1)\n        .ok_or_else(|| anyhow!(\"Failed to capture second group - issue id like \\\"2263\\\"\"))?\n        .as_str()\n        .to_string();\n\n    let issue_labels = GITHUB_ISSUE_LABELS_FETCHER\n        .lock()\n        .map_err(|err| anyhow!(\"Failed to lock GITHUB_ISSUE_LABELS_FETCHER: {err}\"))?\n        .fetch_issue_labels(issue_id.clone(), token)\n        .with_context(|| format!(\"Could not find GitHub labels for issue: {issue_id}\"))?;\n\n    let is_issue_for_this_package = issue_labels\n        .iter()\n        .any(|label| package_labels.contains(&label.as_str()));\n\n    if !is_issue_for_this_package {\n        println!(\"Issue {issue_id} is not for {package_labels:?} packages\");\n        let leftovers = issue_labels.iter().filter(|label| {\n            !(label.starts_with(\"A-\") || *label == \"documentation\" || *label == \"meta\")\n        });\n        let count = leftovers.count();\n        if count > 0 {\n            println!(\"Potentially invalidly labeled issue: {issue_id}. Neither A-* (area), documentation nor meta labels found. \\\n            inspect/re-tag at https://github.com/yewstack/yew/issues/{issue_id}\");\n        }\n        return Ok(None);\n    }\n    let is_breaking_change = issue_labels\n        .iter()\n        .any(|label| label.to_lowercase().contains(\"breaking change\"));\n\n    let log_line = LogLine {\n        message,\n        user: author_name.to_string(),\n        user_id: author_id.to_string(),\n        issue_id,\n        is_breaking_change,\n    };\n\n    println!(\"{log_line:?}\");\n\n    Ok(Some(log_line))\n}\n"
  },
  {
    "path": "tools/changelog/src/create_log_lines.rs",
    "content": "use anyhow::{Context, Result};\nuse git2::{Repository, Sort};\n\nuse crate::create_log_line::create_log_line;\nuse crate::github_user_fetcher::GitHubUsersFetcher;\nuse crate::log_line::LogLine;\n\npub fn create_log_lines(\n    from: String,\n    to: String,\n    package_labels: &'static [&'static str],\n    token: Option<String>,\n) -> Result<Vec<LogLine>> {\n    let repo = Repository::open_from_env()?;\n\n    let mut user_fetcher = GitHubUsersFetcher::default();\n    let from_oid = repo\n        .revparse_single(&from)\n        .context(\"Could not find `from` revision\")?\n        .id();\n    let to_oid = repo\n        .revparse_single(&to)\n        .context(\"Could not find `to` revision\")?\n        .id();\n\n    let mut revwalk = repo.revwalk()?;\n    revwalk.set_sorting(Sort::TOPOLOGICAL)?;\n\n    revwalk.hide(from_oid)?;\n    revwalk.push(to_oid)?;\n\n    revwalk\n        .filter_map(|oid| {\n            create_log_line(&repo, package_labels, oid, token.clone(), &mut user_fetcher)\n                .transpose()\n        })\n        .collect()\n}\n"
  },
  {
    "path": "tools/changelog/src/get_latest_version.rs",
    "content": "use anyhow::{Context, Result};\nuse git2::Repository;\nuse semver::{Error, Version};\n\nuse crate::yew_package::YewPackage;\n\npub fn get_latest_version(package: &YewPackage) -> Result<Version> {\n    let common_tag_pattern = format!(\"{package}-v\");\n    let search_pattern = format!(\"{common_tag_pattern}*\");\n\n    let tags: Vec<Version> = Repository::open_from_env()?\n        .tag_names(Some(&search_pattern))?\n        .iter()\n        .filter_map(|mb_tag| {\n            mb_tag.map(|tag| {\n                let version = tag.replace(&common_tag_pattern, \"\");\n                Version::parse(&version)\n            })\n        })\n        .collect::<Result<Vec<Version>, Error>>()?;\n\n    tags.into_iter().max().context(\"no version found\")\n}\n"
  },
  {
    "path": "tools/changelog/src/github_fetch.rs",
    "content": "use std::thread;\nuse std::time::Duration;\n\nuse anyhow::{bail, Result};\nuse reqwest::blocking::Client;\nuse reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION, USER_AGENT};\nuse serde::de::DeserializeOwned;\n\npub fn github_fetch<T: DeserializeOwned>(url: &str, token: Option<String>) -> Result<T> {\n    thread::sleep(Duration::from_secs(1));\n    let mut optional_headers = HeaderMap::new();\n    if let Some(token) = token {\n        optional_headers.insert(AUTHORIZATION, format!(\"Bearer {token}\").parse().unwrap());\n    }\n\n    let request_client = Client::new();\n    let resp = request_client\n        .get(url)\n        .header(USER_AGENT, \"reqwest\")\n        .header(ACCEPT, \"application/vnd.github.v3+json\")\n        .headers(optional_headers)\n        .send()?;\n    let status = resp.status();\n    if !status.is_success() {\n        if let Some(remaining) = resp.headers().get(\"x-ratelimit-remaining\") {\n            if remaining == \"0\" {\n                bail!(\"GitHub API limit reached.\");\n            }\n        }\n        bail!(\"GitHub API request error: {status}\");\n    }\n    Ok(resp.json()?)\n}\n"
  },
  {
    "path": "tools/changelog/src/github_issue_labels_fetcher.rs",
    "content": "use std::collections::HashMap;\n\nuse anyhow::Result;\nuse serde::Deserialize;\n\nuse super::github_fetch::github_fetch;\n\n#[derive(Deserialize, Debug)]\npub struct BodyListItem {\n    name: String,\n}\n\n#[derive(Debug, Default)]\npub struct GitHubIssueLabelsFetcher {\n    cache: HashMap<String, Option<Vec<String>>>,\n}\n\nimpl GitHubIssueLabelsFetcher {\n    pub fn fetch_issue_labels(\n        &mut self,\n        issue: String,\n        token: Option<String>,\n    ) -> Option<Vec<String>> {\n        self.cache\n            .entry(issue.clone())\n            .or_insert_with(|| match Self::inner_fetch(&issue, token) {\n                Ok(labels) => labels,\n                Err(err) => {\n                    eprintln!(\"fetch_issue_labels Error: {err}\");\n                    None\n                }\n            })\n            .clone()\n    }\n\n    fn inner_fetch(q: &str, token: Option<String>) -> Result<Option<Vec<String>>> {\n        let url = format!(\"https://api.github.com/repos/yewstack/yew/issues/{q}/labels\");\n        let body: Vec<BodyListItem> = github_fetch(&url, token)?;\n        let label_names: Vec<String> = body.into_iter().map(|label| label.name).collect();\n        Ok(Some(label_names))\n    }\n}\n"
  },
  {
    "path": "tools/changelog/src/github_user_fetcher.rs",
    "content": "use std::collections::HashMap;\n\nuse anyhow::Result;\nuse serde::Deserialize;\n\nuse super::github_fetch::github_fetch;\n\n#[derive(Deserialize, Debug)]\nstruct ResponseBody {\n    author: ResponseBodyAuthor,\n}\n\n#[derive(Deserialize, Debug)]\nstruct ResponseBodyAuthor {\n    login: String,\n}\n\n#[derive(Debug, Default)]\npub struct GitHubUsersFetcher {\n    cache: HashMap<String, Option<String>>,\n}\n\nimpl GitHubUsersFetcher {\n    pub fn fetch_user_by_commit_author(\n        &mut self,\n        key: impl Into<String>,\n        commit: impl AsRef<str>,\n        token: Option<String>,\n    ) -> Option<&str> {\n        self.cache\n            .entry(key.into())\n            .or_insert_with(|| match Self::inner_fetch(commit, token) {\n                Ok(value) => value,\n                Err(err) => {\n                    eprintln!(\"fetch_user_by_commit_author Error: {err}\");\n                    None\n                }\n            })\n            .as_deref()\n    }\n\n    fn inner_fetch(commit: impl AsRef<str>, token: Option<String>) -> Result<Option<String>> {\n        let url = format!(\n            \"https://api.github.com/repos/yewstack/yew/commits/{}\",\n            commit.as_ref(),\n        );\n        let body: ResponseBody = github_fetch(&url, token)?;\n        Ok(Some(body.author.login))\n    }\n}\n"
  },
  {
    "path": "tools/changelog/src/lib.rs",
    "content": "mod cli;\npub mod create_log_line;\npub mod create_log_lines;\npub mod get_latest_version;\npub mod github_fetch;\npub mod github_issue_labels_fetcher;\npub mod github_user_fetcher;\npub mod log_line;\npub mod new_version_level;\npub mod stdout_tag_description_changelog;\npub mod write_changelog_file;\npub mod write_log_lines;\npub mod write_version_changelog;\npub mod yew_package;\n\npub use cli::Cli;\n"
  },
  {
    "path": "tools/changelog/src/log_line.rs",
    "content": "#[derive(Debug)]\npub struct LogLine {\n    pub message: String,\n    pub user: String,\n    pub user_id: String,\n    pub issue_id: String,\n    pub is_breaking_change: bool,\n}\n"
  },
  {
    "path": "tools/changelog/src/main.rs",
    "content": "use anyhow::Result;\nuse changelog::Cli;\nuse clap::Parser;\n\nfn main() -> Result<()> {\n    Cli::parse().run()\n}\n"
  },
  {
    "path": "tools/changelog/src/mod.rs",
    "content": "pub mod github_fetch;\npub mod github_issue_labels_fetcher;\npub mod github_user_fetcher;\npub mod log_line;\npub mod yew_package;\n"
  },
  {
    "path": "tools/changelog/src/new_version_level.rs",
    "content": "use semver::Version;\nuse strum::{Display, EnumString};\n\n#[derive(Debug, Clone, EnumString, Display)]\n#[strum(serialize_all = \"lowercase\")]\npub enum NewVersionLevel {\n    Patch,\n    Minor,\n    Major,\n}\n\nimpl NewVersionLevel {\n    pub fn bump(&self, current_version: Version) -> Version {\n        match self {\n            NewVersionLevel::Patch => Version {\n                patch: current_version.patch + 1,\n                ..current_version\n            },\n            NewVersionLevel::Minor => Version {\n                minor: current_version.minor + 1,\n                patch: 0,\n                ..current_version\n            },\n            NewVersionLevel::Major => Version {\n                major: current_version.major + 1,\n                minor: 0,\n                patch: 0,\n                ..current_version\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "tools/changelog/src/stdout_tag_description_changelog.rs",
    "content": "use std::io::{stdout, Write};\n\nuse anyhow::Result;\n\npub fn stdout_tag_description_changelog(\n    fixes_logs: &[u8],\n    features_logs: &[u8],\n    breaking_changes_logs: &[u8],\n) -> Result<()> {\n    let mut tag_changelog = Vec::new();\n\n    writeln!(tag_changelog, \"# Changelog\")?;\n    writeln!(tag_changelog)?;\n\n    if fixes_logs.is_empty() && features_logs.is_empty() && breaking_changes_logs.is_empty() {\n        writeln!(tag_changelog, \"No changes\")?;\n        writeln!(tag_changelog)?;\n    }\n\n    if !fixes_logs.is_empty() {\n        writeln!(tag_changelog, \"### 🛠 Fixes\")?;\n        writeln!(tag_changelog)?;\n        tag_changelog.extend(fixes_logs);\n        writeln!(tag_changelog)?;\n    }\n\n    if !features_logs.is_empty() {\n        writeln!(tag_changelog, \"### ⚡️ Features\")?;\n        writeln!(tag_changelog)?;\n        tag_changelog.extend(features_logs);\n    }\n\n    if !breaking_changes_logs.is_empty() {\n        writeln!(tag_changelog, \"### 🚨 Breaking changes\")?;\n        writeln!(tag_changelog)?;\n        tag_changelog.extend(breaking_changes_logs);\n    }\n\n    stdout().write_all(&tag_changelog)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tools/changelog/src/write_changelog_file.rs",
    "content": "use std::fs;\nuse std::fs::File;\nuse std::io::{BufRead, BufReader, Write};\n\nuse anyhow::{Context, Result};\n\npub fn write_changelog(changelog_path: &str, version_changelog: &[u8]) -> Result<()> {\n    let old_changelog = File::open(changelog_path)\n        .context(format!(\"could not open {changelog_path} for reading\"))?;\n    let old_changelog_reader = BufReader::new(old_changelog);\n\n    let changelog_path_new = &format!(\"{changelog_path}.new\");\n\n    let mut new_changelog = fs::OpenOptions::new()\n        .write(true)\n        .create(true)\n        .truncate(true)\n        .open(changelog_path_new)\n        .context(format!(\"could not open {changelog_path_new} for writing\"))?;\n\n    new_changelog.write_all(version_changelog)?;\n\n    for old_line in old_changelog_reader.lines().skip(2) {\n        writeln!(new_changelog, \"{}\", old_line?)?;\n    }\n\n    drop(new_changelog);\n\n    fs::remove_file(changelog_path).context(format!(\"Could not delete {changelog_path}\"))?;\n    fs::rename(changelog_path_new, changelog_path).context(format!(\n        \"Could not replace {changelog_path} with {changelog_path_new}\"\n    ))?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tools/changelog/src/write_log_lines.rs",
    "content": "use std::io::Write;\n\nuse anyhow::Result;\n\nuse crate::log_line::LogLine;\n\npub fn write_log_lines(log_lines: Vec<LogLine>) -> Result<Vec<u8>> {\n    let mut logs_list = Vec::default();\n    for LogLine {\n        message,\n        user,\n        issue_id,\n        user_id,\n        ..\n    } in log_lines\n    {\n        writeln!(\n            logs_list,\n            \"- {message}. [[@{user}](https://github.com/{user_id}), [#{issue_id}](https://github.com/yewstack/yew/pull/{issue_id})]\",\n        )?;\n    }\n    Ok(logs_list)\n}\n"
  },
  {
    "path": "tools/changelog/src/write_version_changelog.rs",
    "content": "use std::io::Write;\n\nuse anyhow::Result;\nuse semver::Version;\n\nuse crate::yew_package::YewPackage;\n\npub fn write_changelog_file(\n    fixes_logs: &[u8],\n    features_logs: &[u8],\n    breaking_changes_logs: &[u8],\n    package: YewPackage,\n    next_version: Version,\n) -> Result<Vec<u8>> {\n    let mut version_only_changelog = Vec::default();\n\n    writeln!(version_only_changelog, \"# Changelog\")?;\n    writeln!(version_only_changelog)?;\n\n    writeln!(\n        version_only_changelog,\n        \"## ✨ {package} **{next_version}** *({release_date})*\",\n        next_version = next_version,\n        package = package,\n        release_date = chrono::Utc::now().format(\"%Y-%m-%d\")\n    )?;\n    writeln!(version_only_changelog)?;\n\n    if fixes_logs.is_empty() && features_logs.is_empty() && breaking_changes_logs.is_empty() {\n        writeln!(version_only_changelog, \"No changes\")?;\n        writeln!(version_only_changelog)?;\n    }\n\n    if !fixes_logs.is_empty() {\n        writeln!(version_only_changelog, \"### 🛠 Fixes\")?;\n        writeln!(version_only_changelog)?;\n        version_only_changelog.extend(fixes_logs);\n        writeln!(version_only_changelog)?;\n    }\n\n    if !features_logs.is_empty() {\n        writeln!(version_only_changelog, \"### ⚡️ Features\")?;\n        writeln!(version_only_changelog)?;\n        version_only_changelog.extend(features_logs);\n        writeln!(version_only_changelog)?;\n    }\n\n    if !breaking_changes_logs.is_empty() {\n        writeln!(version_only_changelog, \"### 🚨 Breaking changes\")?;\n        writeln!(version_only_changelog)?;\n        version_only_changelog.extend(breaking_changes_logs);\n        writeln!(version_only_changelog)?;\n    }\n\n    Ok(version_only_changelog)\n}\n"
  },
  {
    "path": "tools/changelog/src/yew_package.rs",
    "content": "use strum::{Display, EnumString};\n\n#[derive(Debug, Clone, EnumString, Display)]\n#[strum(serialize_all = \"kebab-case\")]\npub enum YewPackage {\n    Yew,\n    YewAgent,\n    YewRouter,\n}\n\nimpl YewPackage {\n    pub fn as_labels(&self) -> &'static [&'static str] {\n        match self {\n            YewPackage::Yew => &[\"A-yew\", \"A-yew-macro\", \"macro\"],\n            YewPackage::YewAgent => &[\"A-yew-agent\"],\n            YewPackage::YewRouter => &[\"A-yew-router\", \"A-yew-router-macro\"],\n        }\n    }\n}\n"
  },
  {
    "path": "tools/changelog/tests/generate_yew_changelog_file.rs",
    "content": "use std::fs;\nuse std::fs::File;\nuse std::io::{BufRead, BufReader};\nuse std::str::FromStr;\n\nuse anyhow::Result;\nuse changelog::new_version_level::NewVersionLevel;\nuse changelog::yew_package::YewPackage;\nuse changelog::Cli;\nuse chrono::Utc;\n\nstruct FileDeleteOnDrop;\n\nimpl Drop for FileDeleteOnDrop {\n    fn drop(&mut self) {\n        fs::remove_file(\"tests/test_changelog.md\").unwrap();\n    }\n}\n\nfn _generate_yew_changelog_file(from: &str, to: &str) -> Result<()> {\n    let cli_args = Cli {\n        package: YewPackage::from_str(\"yew\").unwrap(),\n        new_version_level: NewVersionLevel::Minor,\n        from: Some(from.to_string()),\n        to: to.to_string(),\n        changelog_path: \"tests/test_changelog.md\".to_string(),\n        skip_file_write: false,\n        skip_get_bump_version: true,\n        token: None,\n    };\n\n    cli_args.run().unwrap();\n\n    Ok(())\n}\n\n#[test]\nfn generate_yew_changelog_file() -> Result<()> {\n    // Setup\n    let file_delete_on_drop = FileDeleteOnDrop;\n\n    fs::copy(\"tests/test_base.md\", \"tests/test_changelog.md\")?;\n\n    // Run\n    _generate_yew_changelog_file(\n        \"abeb8bc3f1ffabc8a58bd9ba4430cd091a06335a\",\n        \"d8ec50150ed27e2835bb1def26d2371a8c2ab750\",\n    )?;\n\n    _generate_yew_changelog_file(\n        \"8086a73a217a099a46138f4363411827b18d1cb0\",\n        \"934aedbc8815fd77fc6630b644cfea4f9a071236\",\n    )?;\n\n    // Check\n    let expected = File::open(\"tests/test_expected.md\")?;\n    let expected_reader_lines = BufReader::new(expected).lines();\n\n    let after = File::open(\"tests/test_changelog.md\")?;\n    let after_reader_lines = BufReader::new(after).lines();\n\n    let lines = expected_reader_lines.zip(after_reader_lines);\n\n    for (i, (expected_line, after_line)) in lines.enumerate() {\n        if i == 2 || i == 13 {\n            // these lines have dynamic things that may break the tests\n            let expected_line_updated = expected_line?.replace(\n                \"date_goes_here\",\n                Utc::now().format(\"%Y-%m-%d\").to_string().as_str(),\n            );\n            assert_eq!(expected_line_updated, after_line?);\n        } else {\n            assert_eq!(expected_line?, after_line?);\n        }\n    }\n\n    drop(file_delete_on_drop);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tools/changelog/tests/test_base.md",
    "content": "# Changelog for its generation tests\n\n## ✨ yew **0.19.0** *(2021-11-26)*\n\n#### Changelog\n\n- #### 🛠 Fixes\n\n  - Attempt to fix recursion on display. [[@mibes](https://github.com/mibes), [#2149](https://github.com/yewstack/yew/pull/2149)]\n  - Fix default passive option. [[@mc1098](https://github.com/mc1098), [#2111](https://github.com/yewstack/yew/pull/2111)]\n\n- #### ⚡️ Features\n\n  - Check event bubbling cancellation at each step of propagation. [[@rjmac](https://github.com/rjmac), [#2191](https://github.com/yewstack/yew/pull/2191)]\n  - Add possibility to cancel bubbling. [[@voidpumpkin](https://github.com/voidpumpkin), [#2172](https://github.com/yewstack/yew/pull/2172)]\n"
  },
  {
    "path": "tools/changelog/tests/test_expected.md",
    "content": "# Changelog\n\n## ✨ yew **0.0.0** *(date_goes_here)*\n\n### ⚡️ Features\n\n- Incremental performance improvements to element creation. [[@Greg Johnston](https://github.com/Greg Johnston), [#3169](https://github.com/yewstack/yew/pull/3169)]\n\n### 🚨 Breaking changes\n\n- Enable PartialEq for all virtual dom types. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#3206](https://github.com/yewstack/yew/pull/3206)]\n- Pass hook dependencies as the first function argument. [[@Arniu Tseng](https://github.com/Arniu Tseng), [#2861](https://github.com/yewstack/yew/pull/2861)]\n\n## ✨ yew **0.0.0** *(date_goes_here)*\n\n### 🛠 Fixes\n\n- Fix defaulted type parameter.. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2284](https://github.com/yewstack/yew/pull/2284)]\n\n### ⚡️ Features\n\n- Silence some warnings from derive(Properties). [[@WorldSEnder](https://github.com/WorldSEnder), [#2266](https://github.com/yewstack/yew/pull/2266)]\n- Raw field names in property structs. [[@WorldSEnder](https://github.com/WorldSEnder), [#2273](https://github.com/yewstack/yew/pull/2273)]\n\n## ✨ yew **0.19.0** *(2021-11-26)*\n\n#### Changelog\n\n- #### 🛠 Fixes\n\n  - Attempt to fix recursion on display. [[@mibes](https://github.com/mibes), [#2149](https://github.com/yewstack/yew/pull/2149)]\n  - Fix default passive option. [[@mc1098](https://github.com/mc1098), [#2111](https://github.com/yewstack/yew/pull/2111)]\n\n- #### ⚡️ Features\n\n  - Check event bubbling cancellation at each step of propagation. [[@rjmac](https://github.com/rjmac), [#2191](https://github.com/yewstack/yew/pull/2191)]\n  - Add possibility to cancel bubbling. [[@voidpumpkin](https://github.com/voidpumpkin), [#2172](https://github.com/yewstack/yew/pull/2172)]\n"
  },
  {
    "path": "tools/collect-release-info/Cargo.toml",
    "content": "[package]\nname = \"collect-release-info\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nanyhow.workspace = true\nserde_json.workspace = true\n"
  },
  {
    "path": "tools/collect-release-info/src/main.rs",
    "content": "use std::io::Write;\nuse std::path::Path;\nuse std::process::Command;\nuse std::{env, fs};\n\nuse anyhow::{bail, Context, Result};\nuse serde_json::json;\n\nfn parse_tag(tag: &str) -> Result<(&str, &str)> {\n    let (package, version) = tag\n        .rsplit_once(\"-v\")\n        .context(\"tag must match <package>-v<version>\")?;\n\n    if package.is_empty() || version.is_empty() {\n        bail!(\"tag must match <package>-v<version>, got: {tag}\");\n    }\n\n    Ok((package, version))\n}\n\nfn extract_section(content: &str, package: &str, version: &str) -> Result<String> {\n    let pkg_lower = package.to_lowercase();\n    let version_needle = format!(\"**{version}**\");\n\n    let mut lines = content.lines();\n    let mut found_target = false;\n\n    for line in lines.by_ref() {\n        if !line.starts_with(\"## \") {\n            continue;\n        }\n\n        if !line.contains(\"**\") {\n            bail!(\n                \"unexpected ## header that is not a version header: {:?}\",\n                line\n            );\n        }\n\n        if line.to_lowercase().contains(&pkg_lower) && line.contains(&version_needle) {\n            found_target = true;\n            break;\n        }\n    }\n\n    if !found_target {\n        bail!(\"no changelog section found for {package} {version}\");\n    }\n\n    let mut section_lines: Vec<&str> = Vec::new();\n\n    for line in lines {\n        if line.starts_with(\"## \") {\n            if !line.contains(\"**\") {\n                bail!(\n                    \"unexpected ## header that is not a version header: {:?}\",\n                    line\n                );\n            }\n            break;\n        }\n        section_lines.push(line);\n    }\n\n    let body = section_lines.join(\"\\n\");\n    let trimmed = body.trim();\n\n    if trimmed.is_empty() {\n        bail!(\"changelog section for {package} {version} is empty\");\n    }\n\n    Ok(trimmed.to_string())\n}\n\nfn find_latest_tag(package: &str) -> Result<String> {\n    let output = Command::new(\"git\")\n        .args([\n            \"describe\",\n            \"--tags\",\n            \"--match\",\n            &format!(\"{package}-v*\"),\n            \"--abbrev=0\",\n        ])\n        .output()\n        .context(\"failed to run git describe\")?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        bail!(\"no tag found for package {package}: {stderr}\");\n    }\n\n    Ok(String::from_utf8(output.stdout)?.trim().to_string())\n}\n\nfn count_rust_lines(dir: &Path) -> usize {\n    let Ok(entries) = fs::read_dir(dir) else {\n        return 0;\n    };\n    let mut total = 0;\n    for entry in entries.flatten() {\n        let path = entry.path();\n        if path.is_dir() {\n            total += count_rust_lines(&path);\n        } else if path.extension().and_then(|e| e.to_str()) == Some(\"rs\") {\n            if let Ok(content) = fs::read_to_string(&path) {\n                total += content.lines().count();\n            }\n        }\n    }\n    total\n}\n\nstruct ReleaseInfo {\n    tag: String,\n    package: String,\n    version: String,\n    body: String,\n    line_count: usize,\n}\n\nfn main() -> Result<()> {\n    let packages: Vec<String> = env::args().skip(1).collect();\n    if packages.is_empty() {\n        bail!(\n            \"Usage: collect-release-info <package> [<package>...]\\nExample: collect-release-info \\\n             yew yew-router\"\n        );\n    }\n\n    let changelog = fs::read_to_string(\"CHANGELOG.md\").context(\"failed to read CHANGELOG.md\")?;\n\n    let mut releases = Vec::new();\n\n    for package in &packages {\n        let tag = match find_latest_tag(package) {\n            Ok(tag) => tag,\n            Err(e) => {\n                eprintln!(\"skipping {package}: {e}\");\n                continue;\n            }\n        };\n        let (pkg, version) = parse_tag(&tag)?;\n        let pkg = pkg.to_string();\n        let version = version.to_string();\n\n        let body = match extract_section(&changelog, &pkg, &version) {\n            Ok(section) => section,\n            Err(e) => {\n                eprintln!(\"warning: {e}\");\n                String::new()\n            }\n        };\n\n        let pkg_dir = Path::new(\"packages\").join(package);\n        let line_count = count_rust_lines(&pkg_dir);\n\n        releases.push(ReleaseInfo {\n            tag,\n            package: pkg,\n            version,\n            body,\n            line_count,\n        });\n    }\n\n    releases.sort_by_key(|r| r.line_count);\n\n    let releases_json: Vec<serde_json::Value> = releases\n        .iter()\n        .map(|r| {\n            json!({\n                \"tag\": r.tag,\n                \"name\": format!(\"{} v{}\", r.package, r.version),\n                \"body\": r.body,\n            })\n        })\n        .collect();\n\n    let version_branch = releases.last().map(|r| r.tag.as_str()).unwrap_or(\"\");\n    let releases_str = serde_json::to_string(&releases_json)?;\n\n    if let Ok(path) = env::var(\"GITHUB_OUTPUT\") {\n        let mut file = fs::OpenOptions::new()\n            .append(true)\n            .open(&path)\n            .with_context(|| format!(\"failed to open GITHUB_OUTPUT at {path}\"))?;\n        writeln!(file, \"releases<<RELEASES_EOF\")?;\n        writeln!(file, \"{releases_str}\")?;\n        writeln!(file, \"RELEASES_EOF\")?;\n        writeln!(file, \"version_branch={version_branch}\")?;\n    }\n\n    for r in &releases {\n        eprintln!(\"{}: {} lines\", r.package, r.line_count);\n    }\n    print!(\"{releases_str}\");\n\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_parse_tag() {\n        let (pkg, ver) = parse_tag(\"yew-v0.23.0\").unwrap();\n        assert_eq!(pkg, \"yew\");\n        assert_eq!(ver, \"0.23.0\");\n    }\n\n    #[test]\n    fn test_parse_tag_with_hyphenated_package() {\n        let (pkg, ver) = parse_tag(\"yew-router-v0.19.0\").unwrap();\n        assert_eq!(pkg, \"yew-router\");\n        assert_eq!(ver, \"0.19.0\");\n    }\n\n    #[test]\n    fn test_parse_tag_invalid() {\n        assert!(parse_tag(\"yew0.23.0\").is_err());\n        assert!(parse_tag(\"-v0.23.0\").is_err());\n        assert!(parse_tag(\"yew-v\").is_err());\n    }\n\n    #[test]\n    fn test_extract_section_basic() {\n        let content = \"\\\n# Changelog\n\n## ✨ yew **0.23.0** *(2026-04-01)*\n\n### Fixes\n\n- Fixed a bug\n\n### Features\n\n- Added a feature\n\n## ✨ yew **0.22.0** *(2025-12-08)*\n\n### Fixes\n\n- Old fix\n\";\n        let result = extract_section(content, \"yew\", \"0.23.0\").unwrap();\n        assert!(result.contains(\"Fixed a bug\"));\n        assert!(result.contains(\"Added a feature\"));\n        assert!(!result.contains(\"Old fix\"));\n    }\n\n    #[test]\n    fn test_extract_section_not_found() {\n        let content = \"# Changelog\\n\\n## ✨ yew **0.22.0**\\n\\n- stuff\\n\";\n        assert!(extract_section(content, \"yew\", \"0.99.0\").is_err());\n    }\n\n    #[test]\n    fn test_extract_section_empty() {\n        let content = \"\\\n## ✨ yew **0.23.0** *(2026-04-01)*\n\n## ✨ yew **0.22.0** *(2025-12-08)*\n\";\n        assert!(extract_section(content, \"yew\", \"0.23.0\").is_err());\n    }\n\n    #[test]\n    fn test_extract_section_last_in_file() {\n        let content = \"\\\n## ✨ yew **0.23.0** *(2026-04-01)*\n\n### Fixes\n\n- The only fix\n\";\n        let result = extract_section(content, \"yew\", \"0.23.0\").unwrap();\n        assert!(result.contains(\"The only fix\"));\n    }\n\n    #[test]\n    fn test_extract_section_case_insensitive_package() {\n        let content = \"\\\n## ✨ Yew **0.23.0** *(2026-04-01)*\n\n- A change\n\";\n        let result = extract_section(content, \"yew\", \"0.23.0\").unwrap();\n        assert!(result.contains(\"A change\"));\n    }\n\n    #[test]\n    fn test_rejects_malformed_h2() {\n        let content = \"\\\n## ✨ yew **0.23.0** *(2026-04-01)*\n\n## Not a version header\n\n- A change\n\";\n        assert!(extract_section(content, \"yew\", \"0.23.0\").is_err());\n    }\n\n    #[test]\n    fn test_yew_has_more_code_than_yew_agent() {\n        let workspace_root = Path::new(env!(\"CARGO_MANIFEST_DIR\"))\n            .parent()\n            .unwrap()\n            .parent()\n            .unwrap();\n        let yew_lines = count_rust_lines(&workspace_root.join(\"packages/yew\"));\n        let agent_lines = count_rust_lines(&workspace_root.join(\"packages/yew-agent\"));\n        assert!(\n            yew_lines > agent_lines,\n            \"expected yew ({yew_lines}) > yew-agent ({agent_lines})\"\n        );\n    }\n}\n"
  },
  {
    "path": "tools/process-benchmark-results/Cargo.toml",
    "content": "[package]\nname = \"process-benchmark-results\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nanyhow.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nserde_json.workspace = true\n"
  },
  {
    "path": "tools/process-benchmark-results/Makefile.toml",
    "content": "# Extends the root Makefile.toml\n\n[tasks.doc-test]\ncommand = \"echo\"\nargs = [\"No doctests run for process-benchmark-results\"]"
  },
  {
    "path": "tools/process-benchmark-results/README.md",
    "content": "Processes benchmark results\nFrom array of js-framework-benchmark\nInto array that works for https://github.com/marketplace/actions/continuous-benchmark action\n"
  },
  {
    "path": "tools/process-benchmark-results/src/main.rs",
    "content": "use std::collections::HashMap;\nuse std::io;\nuse std::io::{Read, Write};\n\nuse anyhow::Result;\nuse serde::{Deserialize, Serialize};\nuse serde_json::Value;\n\n#[derive(Serialize)]\nstruct GhActionBenchmark {\n    name: String,\n    unit: String,\n    value: Value,\n}\n\n// from https://github.com/krausest/js-framework-benchmark/blob/master/webdriver-ts/src/writeResults.ts#L67 function createResultFile\n#[derive(Deserialize)]\nstruct ResultData {\n    median: Value,\n    // some keys missing\n}\n\n#[derive(Deserialize)]\nstruct JsKrauseBenchmarkResult<'r> {\n    framework: &'r str,\n    benchmark: &'r str,\n    r#type: &'r str,\n    values: HashMap<&'r str, ResultData>,\n}\n\nfn transform_results(mut result: JsKrauseBenchmarkResult<'_>) -> GhActionBenchmark {\n    let key = if result.r#type == \"cpu\" {\n        \"total\"\n    } else {\n        \"DEFAULT\"\n    };\n    let values = result.values.remove(key).unwrap_or_else(|| {\n        panic!(\n            \"Expect benchmark data to be present for type {}. Found keys: {:?}, expected {key:?}\",\n            result.r#type,\n            result.values.keys().cloned().collect::<Vec<_>>(),\n        )\n    });\n    assert!(\n        values.median.is_number(),\n        \"expected a numerical benchmark value\"\n    );\n    GhActionBenchmark {\n        name: format!(\"{} {}\", result.framework, result.benchmark).replace('\"', \"\"),\n        unit: String::default(),\n        value: values.median,\n    }\n}\n\nfn main() -> Result<()> {\n    let mut buffer = \"\".to_string();\n    io::stdin().read_to_string(&mut buffer)?;\n\n    let input_json: Vec<_> = serde_json::from_str(buffer.as_str())?;\n\n    let transformed_benchmarks: Vec<GhActionBenchmark> =\n        input_json.into_iter().map(transform_results).collect();\n\n    let output = serde_json::to_string(&transformed_benchmarks)?;\n\n    io::stdout().write_all(output.as_bytes())?;\n    Ok(())\n}\n"
  },
  {
    "path": "tools/ssr-e2e/Cargo.toml",
    "content": "[package]\nname = \"ssr-e2e\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nclap = { workspace = true }\ntokio = { workspace = true, features = [\"macros\", \"rt-multi-thread\", \"process\", \"time\", \"signal\"] }\nreqwest = { workspace = true }\n\n[target.'cfg(unix)'.dependencies]\nlibc = \"0.2\"\n"
  },
  {
    "path": "tools/ssr-e2e/src/main.rs",
    "content": "use std::process::ExitCode;\nuse std::time::Duration;\n\nuse clap::Parser;\nuse tokio::process::{Child, Command};\nuse tokio::time::{sleep, Instant};\n\n#[derive(Parser)]\nstruct Args {\n    /// Shell command to start the SSR server\n    #[clap(long)]\n    server_cmd: String,\n\n    /// URL to poll until the server is ready (expects HTTP 200)\n    #[clap(long)]\n    health_url: String,\n\n    /// Cargo package name whose tests to run\n    #[clap(long)]\n    test_pkg: String,\n\n    /// Directory containing a Trunk project (index.html).\n    /// If provided, `trunk build` is run here before starting the server.\n    #[clap(long)]\n    trunk_dir: Option<String>,\n\n    /// Max seconds to wait for the server to become ready\n    #[clap(long, default_value_t = 120)]\n    timeout: u64,\n\n    /// Extra arguments passed to `cargo test`\n    #[clap(last = true)]\n    extra_args: Vec<String>,\n}\n\nasync fn run_trunk_build(dir: &str) -> bool {\n    eprintln!(\"[ssr-e2e] Running trunk build in {dir} ...\");\n\n    let status = Command::new(\"trunk\")\n        .args([\"build\"])\n        .current_dir(dir)\n        .status()\n        .await;\n\n    match status {\n        Ok(s) if s.success() => {\n            eprintln!(\"[ssr-e2e] trunk build succeeded.\");\n            true\n        }\n        Ok(s) => {\n            eprintln!(\n                \"[ssr-e2e] trunk build failed with exit code: {}\",\n                s.code().unwrap_or(-1)\n            );\n            false\n        }\n        Err(e) => {\n            eprintln!(\"[ssr-e2e] Failed to run trunk build: {e}\");\n            false\n        }\n    }\n}\n\nasync fn wait_for_server(url: &str, timeout: Duration) -> bool {\n    let client = reqwest::Client::builder()\n        .timeout(Duration::from_secs(2))\n        .build()\n        .unwrap();\n\n    let start = Instant::now();\n    let mut interval = Duration::from_millis(100);\n\n    while start.elapsed() < timeout {\n        if let Ok(resp) = client.get(url).send().await {\n            if resp.status().is_success() {\n                return true;\n            }\n        }\n        sleep(interval).await;\n        interval = (interval * 2).min(Duration::from_secs(2));\n    }\n    false\n}\n\n/// Terminates the server and all its descendant processes.\n///\n/// The server is started via `sh -c \"...\"`, producing a process tree\n/// (sh -> cargo run -> server binary). `Child::kill()` alone would only\n/// kill `sh`, orphaning the actual server process on the port. On Unix we\n/// use process groups (set up via `process_group(0)` at spawn time) so a\n/// single `kill(-pgid, SIGTERM)` reaches the entire tree.\nfn shutdown_server(server: &mut Child) {\n    #[cfg(unix)]\n    if let Some(id) = server.id() {\n        let _ = unsafe { libc::kill(-(id as i32), libc::SIGTERM) };\n        return;\n    }\n\n    let _ = server.start_kill();\n}\n\n#[tokio::main]\nasync fn main() -> ExitCode {\n    let args = Args::parse();\n\n    if let Some(ref trunk_dir) = args.trunk_dir {\n        if !run_trunk_build(trunk_dir).await {\n            return ExitCode::FAILURE;\n        }\n    }\n\n    eprintln!(\"[ssr-e2e] Starting server: {}\", args.server_cmd);\n\n    let mut server = {\n        let mut cmd = Command::new(\"sh\");\n        cmd.args([\"-c\", &args.server_cmd]);\n        #[cfg(unix)]\n        cmd.process_group(0);\n        cmd.spawn().expect(\"failed to start server process\")\n    };\n\n    eprintln!(\"[ssr-e2e] Waiting for server at {} ...\", args.health_url);\n\n    let ready = wait_for_server(&args.health_url, Duration::from_secs(args.timeout)).await;\n    if !ready {\n        eprintln!(\n            \"[ssr-e2e] Server did not become ready within {}s\",\n            args.timeout\n        );\n        shutdown_server(&mut server);\n        let _ = server.wait().await;\n        return ExitCode::FAILURE;\n    }\n\n    eprintln!(\n        \"[ssr-e2e] Server is ready. Running tests for {} ...\",\n        args.test_pkg\n    );\n\n    let mut cargo_args = vec![\"test\".to_string(), \"-p\".to_string(), args.test_pkg.clone()];\n    cargo_args.extend(args.extra_args);\n\n    let test_result = Command::new(\"cargo\")\n        .args(&cargo_args)\n        .env(\"WASM_BINDGEN_TEST_NO_ORIGIN_ISOLATION\", \"1\")\n        .status()\n        .await;\n\n    eprintln!(\"[ssr-e2e] Shutting down server ...\");\n    shutdown_server(&mut server);\n    let _ = server.wait().await;\n\n    match test_result {\n        Ok(status) if status.success() => {\n            eprintln!(\"[ssr-e2e] Tests passed.\");\n            ExitCode::SUCCESS\n        }\n        Ok(status) => {\n            eprintln!(\n                \"[ssr-e2e] Tests failed with exit code: {}\",\n                status.code().unwrap_or(-1)\n            );\n            ExitCode::FAILURE\n        }\n        Err(e) => {\n            eprintln!(\"[ssr-e2e] Failed to run tests: {e}\");\n            ExitCode::FAILURE\n        }\n    }\n}\n"
  },
  {
    "path": "tools/ssr-e2e-harness/Cargo.toml",
    "content": "[package]\nname = \"ssr-e2e-harness\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\ngloo = { workspace = true, features = [\"futures\"] }\nweb-sys = { workspace = true }\nwasm-bindgen = { workspace = true }\n"
  },
  {
    "path": "tools/ssr-e2e-harness/src/lib.rs",
    "content": "use std::time::Duration;\n\nuse gloo::utils::document;\nuse wasm_bindgen::prelude::*;\n\n/// Returns the `<div id=\"output\">` element used by wasm-bindgen-test as the\n/// test output container.\npub fn output_element() -> web_sys::Element {\n    document().get_element_by_id(\"output\").unwrap()\n}\n\n/// Fetches an SSR-rendered page from the server and returns the inner HTML\n/// between `<body>` and `</body>`.\npub async fn fetch_ssr_html(server_base: &str, path: &str) -> String {\n    let url = format!(\"{server_base}{path}\");\n    let resp = gloo::net::http::Request::get(&url)\n        .send()\n        .await\n        .expect(\"failed to fetch SSR page\");\n    let html = resp.text().await.expect(\"failed to read SSR response body\");\n    let body_start = html.find(\"<body>\").expect(\"no <body> in SSR HTML\") + \"<body>\".len();\n    let body_end = html.find(\"</body>\").expect(\"no </body> in SSR HTML\");\n    html[body_start..body_end].to_string()\n}\n\n/// Polls `predicate` every 100ms until it returns `true` or `timeout_ms`\n/// elapses, in which case it panics with `desc`.\npub async fn wait_for<F: Fn() -> bool>(predicate: F, timeout_ms: u64, desc: &str) {\n    let step = Duration::from_millis(100);\n    let mut elapsed = Duration::ZERO;\n    let timeout = Duration::from_millis(timeout_ms);\n    while elapsed < timeout {\n        if predicate() {\n            return;\n        }\n        gloo::timers::future::sleep(step).await;\n        elapsed += step;\n    }\n    panic!(\"{desc} did not become true within {timeout_ms}ms\");\n}\n\n/// Fetches SSR HTML for `path`, injects it into the output element, and\n/// pushes the route onto the browser history stack.\npub async fn setup_ssr_page(server_base: &str, path: &str) {\n    let body_html = fetch_ssr_html(server_base, path).await;\n    output_element().set_inner_html(&body_html);\n    push_route(path);\n}\n\n/// Pushes a new entry onto the browser's history stack without navigation.\npub fn push_route(path: &str) {\n    web_sys::window()\n        .unwrap()\n        .history()\n        .unwrap()\n        .push_state_with_url(&JsValue::NULL, \"\", Some(path))\n        .unwrap();\n}\n"
  },
  {
    "path": "tools/website-test/Cargo.toml",
    "content": "[package]\nname = \"website-test\"\nversion = \"0.1.0\"\nedition = \"2021\"\nbuild = \"build.rs\"\npublish = false\nrust-version = \"1.84.0\"\n\n[dependencies]\nyew-agent = { path = \"../../packages/yew-agent/\" }\n\n[dev-dependencies]\nderive_more = { version = \"2.1\", features = [\"from\"] }\ngloo.workspace = true\ngloo-net = \"0.6\"\njs-sys.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nwasm-bindgen.workspace = true\nwasm-bindgen-futures.workspace = true\nweblog = \"0.3.0\"\nyew = { path = \"../../packages/yew/\", features = [\"ssr\", \"csr\", \"serde\"] }\nyew-autoprops = \"0.4.1\"\nyew-router = { path = \"../../packages/yew-router/\" }\ntokio = { workspace = true, features = [\"rt\", \"macros\"] }\n\n[dev-dependencies.web-sys]\nworkspace = true\nfeatures = [\n    \"Document\",\n    \"Element\",\n    \"EventTarget\",\n    \"HtmlElement\",\n    \"HtmlInputElement\",\n    \"HtmlSelectElement\",\n    \"DomRect\",\n]\n\n[build-dependencies]\nglob = \"0.3\"\n"
  },
  {
    "path": "tools/website-test/Makefile.toml",
    "content": "[tasks.doc-test]\ncommand = \"cargo\"\nargs = [\n\t\"test\"\n]"
  },
  {
    "path": "tools/website-test/build.rs",
    "content": "use std::collections::HashMap;\nuse std::error::Error;\nuse std::fmt::Write;\nuse std::fs::File;\nuse std::io::{self, BufRead, BufReader, ErrorKind, Read, Seek, SeekFrom};\nuse std::path::{Path, PathBuf};\nuse std::process::ExitCode;\nuse std::{env, fs};\n\nuse glob::glob;\n\ntype Result<T = ()> = core::result::Result<T, Box<dyn Error + 'static>>;\n\nmacro_rules! e {\n    ($($fmt:tt),* $(,)?) => {\n        return Err(format!($($fmt),*).into())\n    };\n}\n\nmacro_rules! assert {\n    ($condition:expr, $($fmt:tt),* $(,)?) => {\n        if !$condition { e!($($fmt),*) }\n    };\n}\n\n#[derive(Debug, Default)]\nstruct Level {\n    nested: HashMap<String, Level>,\n    files: Vec<PathBuf>,\n}\n\nfn should_combine_code_blocks(path: &Path) -> io::Result<bool> {\n    const FLAG: &[u8] = b\"<!-- COMBINE CODE BLOCKS -->\";\n\n    let mut file = File::open(path)?;\n    match file.seek(SeekFrom::End(-32)) {\n        Ok(_) => (),\n        Err(e) if e.kind() == ErrorKind::InvalidInput => return Ok(false),\n        Err(e) => return Err(e),\n    }\n    let mut buf = [0u8; 32];\n    file.read_exact(&mut buf)?;\n    Ok(buf.trim_ascii_end().ends_with(FLAG))\n}\n\nfn apply_diff(src: &mut String, preamble: &str, added: &str, removed: &str) -> Result {\n    assert!(\n        !preamble.is_empty() || !removed.is_empty(),\n        \"Failure on applying a diff: \\nNo preamble or text to remove provided, unable to find \\\n         location to insert:\\n{added}\\nIn the following text:\\n{src}\",\n    );\n\n    let mut matches = src\n        .match_indices(preamble)\n        .filter_map(|(chunk_start, chunk)| {\n            let removed_start = chunk_start + chunk.len();\n            let removed_end = removed_start + removed.len();\n            src.get(removed_start..removed_end)\n                .eq(&Some(removed))\n                .then_some((removed_start, removed_end))\n        });\n\n    let Some((removed_start, removed_end)) = matches.next() else {\n        e!(\n            \"Failure on applying a diff: \\nCouldn't find the following preamble:\\n{preamble}\\nIn \\\n             the following text:\\n{src}\\nWhile trying to remove the following \\\n             text:\\n{removed}\\nAnd add the following:\\n{added}\"\n        )\n    };\n\n    assert!(\n        matches.next().is_none(),\n        \"Failure on applying a diff: \\nAmbiguous preamble:\\n{preamble}\\nIn the following \\\n         text:\\n{src}\\nWhile trying to remove the following text:\\n{removed}\\nAnd add the \\\n         following:\\n{added}\"\n    );\n\n    src.replace_range(removed_start..removed_end, added);\n    Ok(())\n}\n\nfn combined_code_blocks(path: &Path) -> Result<String> {\n    let file = BufReader::new(File::open(path)?);\n    let mut res = String::new();\n\n    let mut err = Ok(());\n    let mut lines = file\n        .lines()\n        .filter_map(|i| i.map_err(|e| err = Err(e)).ok());\n    while let Some(line) = lines.next() {\n        if !line.starts_with(\"```rust\") {\n            continue;\n        }\n\n        let mut preamble = String::new();\n        let mut added = String::new();\n        let mut removed = String::new();\n        let mut diff_applied = false;\n        for line in &mut lines {\n            if line.starts_with(\"```\") {\n                if !added.is_empty() || !removed.is_empty() {\n                    apply_diff(&mut res, &preamble, &added, &removed)?;\n                } else if !diff_applied {\n                    // if no diff markers were found, just add the contents\n                    res += &preamble;\n                }\n                break;\n            } else if let Some(line) = line.strip_prefix('+') {\n                if line.starts_with(char::is_whitespace) {\n                    added += \" \";\n                }\n                added += line;\n                added += \"\\n\";\n            } else if let Some(line) = line.strip_prefix('-') {\n                if line.starts_with(char::is_whitespace) {\n                    removed += \" \";\n                }\n                removed += line;\n                removed += \"\\n\";\n            } else if line.trim_ascii() == \"// ...\" {\n                // disregard the preamble\n                preamble.clear();\n            } else {\n                if !added.is_empty() || !removed.is_empty() {\n                    diff_applied = true;\n                    apply_diff(&mut res, &preamble, &added, &removed)?;\n                    preamble += &added;\n                    added.clear();\n                    removed.clear();\n                }\n                preamble += &line;\n                preamble += \"\\n\";\n            }\n        }\n    }\n\n    Ok(res)\n}\n\nimpl Level {\n    fn insert(&mut self, path: PathBuf, rel: &[&str]) {\n        if rel.len() == 1 {\n            self.files.push(path);\n        } else {\n            let nested = self.nested.entry(rel[0].to_string()).or_default();\n            nested.insert(path, &rel[1..]);\n        }\n    }\n\n    fn to_contents(&self) -> Result<String> {\n        let mut dst = String::new();\n\n        self.write_inner(&mut dst, 0)?;\n        Ok(dst)\n    }\n\n    fn write_into(&self, dst: &mut String, name: &str, level: usize) -> Result {\n        self.write_space(dst, level);\n        let name = name.replace(['-', '.'], \"_\");\n        writeln!(dst, \"pub mod {name} {{\")?;\n\n        self.write_inner(dst, level + 1)?;\n\n        self.write_space(dst, level);\n        writeln!(dst, \"}}\")?;\n\n        Ok(())\n    }\n\n    fn write_inner(&self, dst: &mut String, level: usize) -> Result {\n        for (name, nested) in &self.nested {\n            nested.write_into(dst, name, level)?;\n        }\n\n        for file in &self.files {\n            let stem = file\n                .file_stem()\n                .ok_or_else(|| format!(\"no filename in path {file:?}\"))?\n                .to_str()\n                .ok_or_else(|| format!(\"non-UTF8 path: {file:?}\"))?\n                .replace('-', \"_\");\n\n            if should_combine_code_blocks(file)? {\n                let res = combined_code_blocks(file)?;\n                self.write_space(dst, level);\n                writeln!(dst, \"/// ```rust, no_run\")?;\n                for line in res.lines() {\n                    self.write_space(dst, level);\n                    writeln!(dst, \"/// {line}\")?;\n                }\n                self.write_space(dst, level);\n                writeln!(dst, \"/// ```\")?;\n            } else {\n                self.write_space(dst, level);\n                writeln!(dst, \"#[doc = include_str!(r\\\"{}\\\")]\", file.display())?;\n            }\n            self.write_space(dst, level);\n            writeln!(dst, \"pub fn {stem}_md() {{}}\")?;\n        }\n\n        Ok(())\n    }\n\n    fn write_space(&self, dst: &mut String, level: usize) {\n        for _ in 0..level {\n            dst.push_str(\"    \");\n        }\n    }\n}\n\nfn inner_main() -> Result {\n    let home = env::var(\"CARGO_MANIFEST_DIR\")?;\n    let pattern = format!(\"{home}/../../website/docs/**/*.md*\");\n    let base = format!(\"{home}/../../website\");\n    let base = Path::new(&base).canonicalize()?;\n    let dir_pattern = format!(\"{home}/../../website/docs/**\");\n    for dir in glob(&dir_pattern)? {\n        println!(\"cargo:rerun-if-changed={}\", dir?.display());\n    }\n\n    let mut level = Level::default();\n\n    for entry in glob(&pattern)? {\n        let path = entry?.canonicalize()?;\n        println!(\"cargo:rerun-if-changed={}\", path.display());\n        let rel = path.strip_prefix(&base)?;\n\n        let mut parts = vec![];\n\n        for part in rel {\n            parts.push(\n                part.to_str()\n                    .ok_or_else(|| format!(\"Non-UTF8 path: {rel:?}\"))?,\n            );\n        }\n\n        level.insert(path.clone(), &parts[..]);\n    }\n\n    let out = format!(\"{}/website_tests.rs\", env::var(\"OUT_DIR\")?);\n\n    fs::write(out, level.to_contents()?)?;\n    Ok(())\n}\n\nfn main() -> ExitCode {\n    match inner_main() {\n        Ok(_) => ExitCode::SUCCESS,\n        Err(e) => {\n            eprintln!(\"{e}\");\n            ExitCode::FAILURE\n        }\n    }\n}\n"
  },
  {
    "path": "tools/website-test/src/lib.rs",
    "content": "include!(concat!(env!(\"OUT_DIR\"), \"/website_tests.rs\"));\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/.prettierignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# it messes these files\nREADME.md\ni18n/**/*.json\n"
  },
  {
    "path": "website/.prettierrc.json",
    "content": "{\n    \"trailingComma\": \"es5\",\n    \"tabWidth\": 4,\n    \"semi\": false,\n    \"singleQuote\": true\n}\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.\n\nMost of the content sits inside the [docs](docs) folder and the [versioned_docs](versioned_docs) folder in the form of\nmarkdown.\n\n## Installation\n\n```console\nnpm install\n```\n\n## Local Development\n\n```console\nnpm start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live\nwithout having to restart the server.\nNote this only builds for English locale unlike a production build.\n\n> Documentation is written in `mdx`, a superset of markdown empowered with jsx.\n> JetBrains and VSCode both provide MDX plugins.\n\n## Testing\n\n```console\ncargo make website-test\n```\n\n[`website-test`](../tools/website-test) is a tool to test all code blocks in the docs as Rust doctests.\nIt gathers the Rust code blocks automatically, but by default they're all tested separate. In case of a \nwalkthrough, it makes more sense to combine the changes described in the blocks & test the code as one.\nFor this end `website-test` scans all doc files for a special flag:\n\n```html\n<!-- COMBINE CODE BLOCKS -->\n```\nIf a file ends with this specific comment (and an optional newline after it), all code blocks will be\nsown together, with respect to the diff markers in them. For example:\n\n```md\n\\`\\`\\`rust\nfn main() {\n    println!(\"Hello, World\");\n}\n\\`\\`\\`\n\n\\`\\`\\`rust\nfn main() {\n-   println!(\"Hello, World\");\n+   println!(\"Goodbye, World\");\n}\n\\`\\`\\`\n\n<!-- COMBINE CODE BLOCKS -->\n```\n\nWill be tested as:\n```rust\nfn main() {\n    println!(\"Goodbye, World\");\n}\n```\n\n:::warning\nThe current implementation only uses the code before the diff or the code to remove as context,\nso make sure there's enough of it. The test assembler will tell you if there isn't.\n:::\n\nWhile assembling the code blocks, the test assembler will put special meaning into a code\nline `// ...`. This line tells the test assembler to disregard any previous context for applying a diff\n\n## Production Build\n\n```console\nnpm run build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n## Localization\n\nLocalization is done on [GitLocalize](https://gitlocalize.com/repo/7052/whole_project).\nYou can sign in with your GitHub account to start translating.\n\nWhen you add to the docs in the `mdx` files,  \nContributors on GitLocalize will translate the added content\nand the translation will get dumped under the [i18n](i18n) folder in a later time.\n\nIf you are a native speaker of one of the translated languages,\nand you are interested in translating your edits yourself,\nyou are welcome to navigate to the folder and do it yourself!\n\n### Localizing headings\n\nIf you want to write displayed content in `html/jsx` instead of vanilla markdown,\nYou should wrap your text in `<Translate/>` tags.\nIt helps docusaurus to extract those texts and compile them to `.json` files to\nget further translated in GitLocalize.\n\n```jsx\nimport Translate from '@docusaurus/Translate'\n\n<h2>\n    <Translate id=\"header.translation.id\" description=\"the heading description\">\n        This heading will be translated\n    </Translate>\n</h2>\n```\n\nIf your pull request adds new `<Translation>` tags,\nmake sure you do `npm run write-translations` to generate the new stubs for later localization.\nAnd you are always welcome to add localization yourself in your native languages!\n\n### Common issues in localization\n\nPages (.mdx) are translated one-to-one and the english text is used as fallback if no translation\nexists. Sometimes, when building you might see a warning, and subsequent error,\nlike this\n\n> [WARNING] Docs markdown link couldn't be resolved: (../components/refs.mdx) in\n> <omitted>/yew/website/versioned_docs/version-0.18.0/concepts/html/events.mdx for version 0.18.0\n\nThis means that the _non-translated_ page at `versioned_docs/version-0.18.0/concepts/html/events.mdx`\ncontains a relative link - `../components/refs.mdx` - to a page that _has_ been translated.\nChange the link to be relative to the doc root folder, in this case `concepts/components/res.mdx`, or,\nif you find the time, also translate the offending page.\n"
  },
  {
    "path": "website/babel.config.js",
    "content": "module.exports = {\n    presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n}\n"
  },
  {
    "path": "website/blog/2022-01-20-hello-yew.md",
    "content": "---\ntitle: Hello Yew\nauthors: [hamza]\n---\n\nThis is the first Yew blog post.\n\n<!--truncate-->\n\nYew is a modern Rust framework for creating multi-threaded front-end web apps with WebAssembly.\n"
  },
  {
    "path": "website/blog/2022-11-24-release-0-20.md",
    "content": "---\ntitle: Releasing Yew 0.20\nauthors: [hamza] tags: [release]\n---\n\nThe Yew team is happy to announce a new, long overdue, version of Yew: v0.20.\nYew is a framework for creating reliable and efficient web applications.\n\n<!--truncate-->\n\n## What's new\n\nThis release comes with new features aimed at improving the user experience, such as server-rendering and render-as-you-fetch approach for data-fetching.\n\n### SSR\n\nYew now fully supports rendering on the server. Rendering on the server means users will get a rendered HTML and will not have to wait to be able to see anything until the entire WebAssembly bundle is downloaded and initial render has completed. With SSR, the page will be visible instantly, and interactable as soon as hydration finishes.\n\nLearn more at [Server-side rendering](/docs/advanced-topics/server-side-rendering)\n\n### Data fetching\n\nWith SSR comes new ways of data-fetching. The newly added [`use_prepared_state!`](https://api.yew.rs/next/yew/functional/macro.use_prepared_state.html) hook can be used to fetch data while rendering on the server and seamlessly use it in the component.\n\nFor client-side fetching, Yew now supports render-as-you-fetch approach with [Suspense](/docs/concepts/suspense).\n\n## How to upgrade\n\nThere have been breaking changes in this release. Our [migration guides](/docs/migration-guides/yew/from-0_19_0-to-0_20_0) go over how to upgrade each over of the new crates.\n\n## Thanks!\n\nMany people came together to help make this release happen. We couldn't have done it without all of you. Thanks!\n"
  },
  {
    "path": "website/blog/2023-09-23-release-0-21.md",
    "content": "---\ntitle: Announcing Yew 0.21\nauthors: [hamza]\n---\n\nThe Yew development team is thrilled to unveil Yew 0.21.0, a significant milestone in the journey of empowering developers to create dependable and high-performance web applications with Rust.\nLet's dive into the major highlights of this release.\n\n<!--truncate-->\n\n## What's new\n\n### 1. Changing Signatures: A Shift in Hook Dependencies\n\nOne of the significant changes in Yew 0.21 is the adjustment to the signature of hooks that accept dependencies.\nDependencies used to be passed as the second argument after the closure. However, now they're passed as the first argument before the closure.\n\n```rust\nuse_effect_with_deps(deps, move |deps: Vec<i32>| {\n    // Do something with dependencies\n});\n```\n\nThe reason behind swapping the order of dependencies in the code snippet is to address a specific use case.\nIn situations where the same value is needed both to compute a dependency and to be moved by value into the closure, the new order simplifies the code and improves readability and ergonomics.\n\nThis is a big breaking change so we've provided [a way to automate the refactor](https://yew.rs/docs/migration-guides/yew/from-0_20_0-to-0_21_0#automated-refactor)\n\n### 2. Versatile Child Types\n\nYew now allows you to use any type as children within your components. This means you're no longer limited to just the `Children` type.\nInstead, you can use any type, even `Html` or closures, unlocking patterns such as:\n\n```rust\nhtml! {\n    <Comp>\n        {|p: RenderProps| html!{<>{\"Hello, \"}{p.name}</>}}\n    </Comp>\n}\n```\n\n### 3. Agents: A Complete Rewrite\n\nYew 0.21 brings a complete rewrite of `yew-agent`. This streamlines and simplifies the way workers operate. Here's what you need to know:\n\n- **Introducing Providers:** Say goodbye to the old `Worker::bridge()` method. Now, you can use the use `WorkerProvider` / `ReactorProvider` / `OneshotProvider` as per your need, by creating them using the hooks.\n\n- **WorkerLink to WorkerScope:** We've removed WorkerLink in favor of WorkerScope. This change simplifies the worker architecture, making it more straightforward to manage and maintain.\n\nThere are now 3 types of agents to be used, depending upon the situation:\n\n- **Worker Agent:** The original agent that uses an actor model, designed to handle complex states.\n\n- **Oneshot Agent:** Designed for scenarios where you expect a single input and a single output for each agent.\n\n- **Reactor Agent:** Ideal for situations where multiple inputs and multiple outputs are needed for each agent.\n\nLearn more in [documentation of yew-agent](https://docs.rs/yew-agent/latest/yew_agent/)\n\n### 4. Performance Improvements: A Faster and Smoother Experience\n\nYew 0.21 brings substantial performance improvements. Your web applications will run faster and more efficiently, thanks to optimizations that reduce memory usage and enhance rendering.\n\n## Call for Contributors\n\nThe Yew project thrives on community involvement, and we welcome contributors with open arms. Whether you're an experienced Rust developer or just starting your journey, there are plenty of ways to get involved and make a meaningful impact on Yew's growth.\n\nHere are some areas where you can contribute:\n\n- **Code Contributions:** If you're passionate about web development with Rust, consider contributing code to Yew. Whether it's fixing bugs, adding new features, or improving documentation, your code can help make Yew even better.\n\n- **Documentation:** Clear and comprehensive documentation is vital for any project's success. You can contribute by improving documentation, writing tutorials, or creating examples that help others understand and use Yew effectively.\n\n- **Testing and Bug Reporting:** Testing Yew and reporting bugs you encounter is a valuable contribution. Your feedback helps us identify and fix issues, ensuring a more stable framework for everyone.\n\n- **Community Support:** Join discussions, chat rooms (we have our own Discord and Matrix!), or social media to assist other developers using Yew. Sharing your knowledge and helping others solve problems is a fantastic way to contribute.\n\nContributing to open-source projects like Yew is not only a way to give back to the community but also an excellent opportunity to learn, collaborate, and enhance your skills.\n\nTo get started, check out the Yew GitHub repository and the contribution guidelines. Your contributions are highly appreciated and play a crucial role in shaping the future of Yew. Join us in this exciting journey!\n\n## Thanks!\n\nMany people came together to create Yew 0.21. We couldn't have done it without all of you. Thanks!\n\nSee [the full changelog](https://github.com/yewstack/yew/blob/master/CHANGELOG.md)\n"
  },
  {
    "path": "website/blog/2024-10-14-release-0-22.md",
    "content": "---\ntitle: Announcing Yew 0.22\nauthors: [langyo]\n---\n\n<!--truncate-->\n\n## What's new\n\n### SSR on WASI\n\nBefore Yew 0.22, server-side rendering (SSR) was only possible on the native target. With Yew 0.22, you can now render your Yew application on the WebAssembly System Interface (WASI) target.\n\nSince the old SSR implementation will create new tasks directly in the asynchronous context directly (based on `prokio`). It only allowed in a multi-threaded environment that it is not compatible with WASI. So the new version added a dedicated one for a single-threaded environment that rendering function to support single-threaded scenes.\n\nLearn more at [Server-side rendering example on WASI environment](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module/src/main.rs)\n\n## Call for Contributors\n\nThe Yew project thrives on community involvement, and we welcome contributors with open arms. Whether you're an experienced Rust developer or just starting your journey, there are plenty of ways to get involved and make a meaningful impact on Yew's growth.\n\nHere are some areas where you can contribute:\n\n- **Code Contributions:** If you're passionate about web development with Rust, consider contributing code to Yew. Whether it's fixing bugs, adding new features, or improving documentation, your code can help make Yew even better.\n\n- **Documentation:** Clear and comprehensive documentation is vital for any project's success. You can contribute by improving documentation, writing tutorials, or creating examples that help others understand and use Yew effectively.\n\n- **Testing and Bug Reporting:** Testing Yew and reporting bugs you encounter is a valuable contribution. Your feedback helps us identify and fix issues, ensuring a more stable framework for everyone.\n\n- **Community Support:** Join discussions, chat rooms (we have our own Discord and Matrix!), or social media to assist other developers using Yew. Sharing your knowledge and helping others solve problems is a fantastic way to contribute.\n\nContributing to open-source projects like Yew is not only a way to give back to the community but also an excellent opportunity to learn, collaborate, and enhance your skills.\n\nTo get started, check out the Yew GitHub repository and the contribution guidelines. Your contributions are highly appreciated and play a crucial role in shaping the future of Yew. Join us in this exciting journey!\n\n## Thanks!\n\nMany people came together to create Yew 0.22. We couldn't have done it without all of you. Thanks!\n\nSee [the full changelog](https://github.com/yewstack/yew/blob/master/CHANGELOG.md)\n"
  },
  {
    "path": "website/blog/2025-11-29-release-0-22.md",
    "content": "---\ntitle: Yew 0.22 - For Real This Time\nauthors: [mattuwu]\n---\n\nThe Yew team is thrilled to announce the release of Yew 0.22! After a longer-than-expected journey, this release brings significant improvements to ergonomics, performance, and developer experience.\n\n<!--truncate-->\n\n## Highlights\n\n### New `#[component]` Attribute\n\nThe `#[function_component]` attribute has been renamed to `#[component]` for brevity:\n\n```rust\n// Before\n#[function_component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello!\"}</div> }\n}\n\n// After (0.22+)\n#[component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello!\"}</div> }\n}\n```\n\nThe old `#[function_component]` attribute is deprecated but still works, giving you time to migrate.\n\n### For-Loops in `html!`\n\nYou can now use for-loops directly in the `html!` macro, making iteration more natural:\n\n```rust\n// Before - using iterator adapters\nhtml! {\n    <ul>\n        { for items.iter().map(|item| html! { <li>{ item }</li> }) }\n    </ul>\n}\n\n// After (0.22+) - native for-loop syntax\nhtml! {\n    <ul>\n        for item in items {\n            <li>{ item }</li>\n        }\n    </ul>\n}\n```\n\n### MSRV Raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. This allows us to use newer language features and provide better error messages.\n\n### WASI Support for SSR\n\nServer-side rendering now works on WASI targets. See the [original 0.22 announcement](/blog/2024/10/14/release-0-22) for details.\n\n### Better Cloning Ergonomics\n\n- `ImplicitClone` is implemented for more yew types. This means less `&` and `*` and `.clone()` clutter in the html macro.\n\n### yew-agent: Vendored gloo-workers\n\nThe `yew-agent` crate now includes its own web worker implementation, removing the external dependency on `gloo-worker`. This also adds support for **module-type web workers**:\n\n```rust\nlet spawner = WorkerSpawner::<MyWorker>::new()\n    .as_module(true)  // Use ES module workers\n    .spawn();\n```\n\n### yew-router: Query Parameter Traits\n\nThe `FromQuery` and `ToQuery` traits from gloo are now re-exported via `yew_router::query` for more flexible query parameter handling, along with dynamic basename support.\n\n## Migration Guide\n\nSee the [migration guide](/docs/next/migration-guides/yew/from-0_21_0-to-0_22_0) for detailed instructions on upgrading from 0.21.\n\n## Contributors\n\nMany thanks to everyone who contributed to this release! Special thanks to:\n\n- [@WorldSEnder](https://github.com/WorldSEnder) for hydration fixes\n- [@its-the-shrimp](https://github.com/its-the-shrimp) for html macro enhancements\n- [@Kirill Semyonkin](https://github.com/kirillsemyonkin) for implicit clone library improvements\n- [@langyo](https://github.com/langyo) for WASI SSR support\n- [@cecton](https://github.com/cecton) for implicit clone improvements and ergonomics\n- [@ranile](https://github.com/ranile) for property improvements\n\nAnd all the other contributors who helped make this release possible!\n\n## What's Next\n\nWe're continuing to work on improving Yew's performance, developer experience, and documentation. Join us on [Discord](https://discord.gg/VQck8X4) to get involved!\n\nSee the [full changelog](https://github.com/yewstack/yew/blob/master/CHANGELOG.md) for all changes.\n"
  },
  {
    "path": "website/blog/authors.yml",
    "content": "hamza:\n    name: Muhammad Hamza\n    title: Maintainer of Yew\n    url: https://github.com/ranile\n    image_url: https://github.com/ranile.png\n\nlangyo:\n    name: langyo\n    title: Contributor of Yew\n    url: https://github.com/langyo\n    image_url: https://github.com/langyo.png\n\nmattuwu:\n    name: Mattuwu\n    title: Maintainer of Yew\n    url: https://github.com/Madoshakalaka\n    image_url: https://github.com/Madoshakalaka.png\n"
  },
  {
    "path": "website/check-translations.js",
    "content": "const {\n    i18n: { defaultLocale, locales },\n} = require('./docusaurus.config.js')\nconst util = require('util')\nconst exec = util.promisify(require('child_process').exec)\nconst path = require('path')\nconst fs = require('fs')\nconst os = require('os')\nconst dircompare = require('dir-compare')\nconst writeTranslations = require('./write-translations.js')\n\nconst VERSION_NAME_CURRENT = 'current'\nconst VERSIONS = (async () => {\n    const listedFiles = await fs.promises.readdir('versioned_docs', {\n        withFileTypes: true,\n    })\n    return [VERSION_NAME_CURRENT].concat(\n        listedFiles.filter((e) => e.isDirectory()).map((e) => e.name)\n    )\n})()\n\nasync function checkSuperfluousTranslations() {\n    const versions = await VERSIONS\n    let success = true\n    for (const locale of locales) {\n        if (locale === defaultLocale) {\n            continue\n        }\n        for (const version of versions) {\n            let isCurrentVersion = version == VERSION_NAME_CURRENT\n            const originDir = isCurrentVersion\n                ? 'docs'\n                : path.join('versioned_docs', version)\n            const localeDir = path.join(\n                'i18n',\n                locale,\n                'docusaurus-plugin-content-docs',\n                version\n            )\n            if (\n                !(await fs.promises.access(localeDir, fs.constants.F_OK).then(\n                    (_) => true,\n                    (_) => false\n                ))\n            ) {\n                console.warn(\n                    `Missing translations for locale ${locale}, version ${version}.`\n                )\n                continue\n            }\n\n            const result = await dircompare.compare(originDir, localeDir)\n            if (!result.diffSet) {\n                throw new Error('Expected diff set')\n            }\n            const superfluous = result.diffSet\n                .filter((e) => e.state === 'right')\n                .map((e) => path.join(e.path2, e.name2))\n            if (superfluous.length > 0) {\n                let severity = isCurrentVersion ? console.error : console.warn\n                severity(\n                    `Found superfluous translations for locale ${locale}, version ${version}:`,\n                    superfluous\n                )\n                if (isCurrentVersion) success = false\n            }\n        }\n    }\n    return success\n}\n\nasync function checkWriteTranslations() {\n    const temp = await fs.promises.mkdtemp(\n        path.join(os.tmpdir(), 'yew-website-')\n    )\n    await new Promise((resolve) => {\n        fs.cp('i18n', temp, { recursive: true }, () => {\n            resolve()\n        })\n    })\n\n    await writeTranslations()\n\n    const result = await dircompare.compare(temp, 'i18n', {\n        compareContent: true,\n    })\n    if (result.same) {\n        console.log('Translations unchanged')\n        return true\n    } else {\n        console.error(\n            'Translations changed, please run `npm run write-translations` to generate the stubs'\n        )\n        return false\n    }\n}\n\nasync function main() {\n    let okay = true\n    okay &= await checkSuperfluousTranslations()\n    okay &= await checkWriteTranslations()\n\n    if (!okay) {\n        process.exitCode = 1\n    }\n}\n\nmain().catch((e) => {\n    console.error(e)\n    process.exitCode = 1\n})\n"
  },
  {
    "path": "website/community/awesome.md",
    "content": "---\ntitle: 'Awesome Yew'\ndescription: 'Community projects built using yew'\n---\n\n## Projects\n\n- [Fullstack application with infrastructure](https://github.com/alelavelli/rust-fullstack-web-application) - Complete production-ready application with `yew` as frontend, `axum` as backend, `docker compose` as infrastructure, `mongodb` as database.\n- [Realworld example](https://github.com/jetli/rust-yew-realworld-example-app) - Exemplary real world app built with Rust + Yew + WebAssembly. It utilizes Yew's latest `function components` and `hooks`. It also supports desktop application powered by [Tauri](https://github.com/tauri-apps/tauri).\n- [webapp.rs](https://github.com/saschagrunert/webapp.rs) - A web application completely written in Rust, frontend is built with Yew.\n- [Rust-Full-Stack](https://github.com/steadylearner/Rust-Full-Stack) - Easily testable and working Rust codes with blog posts to explain them.\n- [Bucket Questions](https://github.com/hgzimmerman/BucketQuestions) - A webapp written entirely in Rust for a dumb party game.\n- [web-view todomvc desktop app](https://github.com/Extrawurst/rust-webview-todomvc-yew) - Demo how to use yew for a todomvc that compiles to WebAssembly and is bundled as a lightweight(~2mb) desktop app by [web-view](https://github.com/Boscop/web-view), as an alternative to Electron, [web-view](https://github.com/Boscop/web-view) also has a [demo](https://github.com/Boscop/web-view/tree/master/webview-examples/examples#todo-yew).\n- [yew-react-example](https://github.com/hobofan/yew-react-example) - This project shows how to create a web app using a React component inside a Yew component.\n- [Kirk](https://github.com/stkevintan/Kirk) - Just A Rust WebAssembly Blog.\n- [rust-async-wasm-demo](https://github.com/extraymond/rust-async-wasm-demo) - Toy project to learn Rust and async that can be deployed to the web.\n- [karaoke-rs](https://github.com/tarkah/karaoke-rs) - A simple, network enabled karaoke player in Rust.\n- [I Love Hue! (rs)](https://github.com/noc7c9/i-love-hue-rs) - A clone of the mobile game I Love Hue in Yew (Rust).\n- [yew-styles-page](https://github.com/spielrs/yew-styles-page) - This is an initial project of a framework style for yew.\n- [caniuse.rs](https://github.com/jplatte/caniuse.rs) - Rust feature search.\n- [Rust electron yew demo](https://github.com/Extrawurst/rust-electron-demo) - An example of building a Rust based web app (Yew) into a native app using electron.\n- [covplot](https://github.com/jbowens/covplot) - Live graphs of worldwide CoVID-19 data.\n- [Tanoshi](https://github.com/fadhlika/tanoshi-web) - Tachiyomi-like web manga reader. Front-end for tanoshi.\n- [Minesweeper](https://github.com/jgpaiva/minesweeper) - Minesweeper built with Rust, Yew and WebAssembly.\n- [Freecell](https://github.com/Stigjb/freecell) - A patience game written in Rust and Yew.\n- [Daydream](https://github.com/MTRNord/Daydream) - A small Matrix web client written in Rust.\n- [Yew-WebRTC-Chat](https://github.com/codec-abc/Yew-WebRTC-Chat) - A simple WebRTC chat made with Yew.\n- [Yew Fullstack Boilerplate](https://github.com/lukidoescode/yew-fullstack-boilerplate) - Highly opinionated boilerplate for creating full stack applications with Rust.\n- [Chord Quiz](https://github.com/Stigjb/chord-quiz) - Practice recognizing chords in this Rust/Yew/WebAssembly app.\n- [RustMart](https://github.com/sheshbabu/rustmart-yew-example) - Single Page Application (SPA) written using Rust, Wasm and Yew.\n- [DevAndDev](https://github.com/alepez/devand) - A website where developers can find pair-programming partners. Written in Rust, Yew frontend.\n- [yew-octicons](https://github.com/io12/yew-octicons) - An easy interface for using Octicons in Yew projects.\n- [Pipe](https://github.com/pipe-fun/pipe) - This is a Rust / Wasm client web app which is a task control center.\n- [note-to-yew](https://github.com/oovm/note-to-yew) - Convert your markups into Yew macro online, which is also made by Yew.\n- [ASCII-Hangman](https://github.com/getreu/ascii-hangman) - Configurable Hangman game for children with ASCII-art rewarding.\n- [dotdotyew](https://github.com/shaunbennett/dotdotyew) - [Dot-voting](https://en.wikipedia.org/wiki/Dot-voting) using Yew, with Rust powering the backend API.\n- [wasm-2048](https://github.com/dev-family/wasm-2048) - 2048 game implemented with Rust and Yew and compiled to Wasm.\n- [website-wasm](https://github.com/kamiyaa/website-wasm) - My personal website written in Rust via Yew/Wasm.\n- [KeyPress](https://github.com/rayylee/keypress) - A Rust WebAssembly Website example for practising english for chinese.\n- [yew-train-ticket](https://github.com/anthhub/yew-train-ticket) - A Rust WebAssembly Webapp example basing Yew newest hooks and functional API, the code style is extremely like React Function Component.\n- [yew-d3-example](https://github.com/ivanschuetz/yew-d3-example) - Showing a d3 chart with Yew.\n- [Oxfeed](https://github.com/sanpii/oxfeed) - A feed reader written in Rust with a Yew frontend.\n- [Flow.er](https://github.com/LighghtEeloo/flow.er) - A notebook app integrated with todo lists utility. Developed with Rust, WebAssembly, Yew and Trunk.\n- [Fullstack-Rust](https://github.com/vascokk/fullstack-rust) - A Full Stack Rust application (Connect5 game) with Actix-web, Yew, Bulma CSS and Diesel.\n- [Sea_battle](https://github.com/MAE664128/sea_battle) - A simple example of a sea battle game. Rust + Yew.\n- [tide-async-graphql-mongodb](https://github.com/zzy/tide-async-graphql-mongodb) - Clean boilerplate for graphql services, with wasm/yew frontend.\n- [surfer](https://github.com/zzy/surfer) - A blog built on yew + graphql, with [live demo site](https://niqin.com). Backend for graphql services, and frontend for web application.\n- [qubit](https://abhimanyu003.github.io/qubit) - A handy calculator, based on Rust and WebAssembly, [Live Demo](https://abhimanyu003.github.io/qubit/).\n- [Paudle](https://github.com/pmsanford/paudle) - A reimplementation of the excellent word game Wordle by Josh Wardle.\n- [Rust algorithms](https://github.com/Jondolf/rust-algorithms) - A website with interactive implementations of various algorithms (only sorting algorithms for now).\n- [Marc Portfolio](https://gitlab.com/marcempunkt/maeurerdev) - A software developer portfolio, [Live Demo](https://maeurer.dev/).\n- [zzhack](https://github.com/zzhack-stack/zzhack) - A personal blog, based on Rust & Yew, [Live Demo](https://www.zzhack.fun/technology).\n- [viz.rs](https://github.com/viz-rs/viz-rs.github.io) - A website for viz web framework, [Live Demo](https://viz.rs/).\n- [hurlurl](https://github.com/lucasmerlin/hurlurl) - A randomizing link shortener, [Live Demo](https://hurlurl.com/).\n- [Macige](https://github.com/tramlinehq/macige) - CI workflow generator for mobile app development, [Live Demo](https://macige.tramline.app).\n- [Spaceman](https://github.com/eliaperantoni/spaceman) - A cross-platform and graphical client for the gRPC communication protocol.\n\n## Templates\n\n- [Create Yew App](https://github.com/jetli/create-yew-app) - Set up a modern Yew web app by running one command, `npx create-yew-app my-app`.\n- [yew-wasm-pack-template](https://github.com/yewstack/yew-wasm-pack-template) - A template for starting a Yew project to be used with wasm-pack.\n- [yew-wasm-pack-minimal](https://github.com/yewstack/yew-wasm-pack-minimal) - A minimal template for starting a Yew project using wasm-bindgen and wasm-pack.\n- [yew-parcel-template](https://github.com/spielrs/yew-parcel-template) - Awesome Yew with Yew-Router and Parcel application.\n\n## Crates\n\n### Component Libraries\n\n- [yew-mdc](https://github.com/dungeonfog/yew-mdc) - Material Design Components for the Yew framework.\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI-CSS Components for Yew framework.\n- [yew-bulma](https://github.com/kellpossible/yew-bulma) - A Rust library providing components based on the bulma css library for projects using Yew.\n- [material-yew](https://github.com/hamza1311/material-yew) - Yew wrapper for Material Web Components.\n- [Yewprint](https://github.com/cecton/yewprint) - Port of blueprintjs.com to Yew.\n- [ybc](https://github.com/thedodd/ybc) - A Yew component library based on the Bulma CSS framework.\n- [patternfly-yew](https://github.com/ctron/patternfly-yew) - Patternfly components for Yew.\n- [yew-feather](https://github.com/pedrodesu/yew-feather) - Feather Icons components for Yew.\n- [tailwind-yew-builder](https://github.com/matiu2/tailwind-yew-builder) - Builds Tailwind CSS for Yew using docker-compose. Also supports Trunk.\n- [yew-components](https://github.com/angular-rust/yew-components) - Material Design Components for the Yew framework.\n- [yew-chart](https://github.com/titanclass/yew-chart) - A Yew-based charting library that provides SVG based components for rendering charts.\n\n### Components\n\n- [Yew Form](https://github.com/jfbilodeau/yew_form) - Components to simplify handling forms with Yew.\n- [yew-component-size](https://github.com/AircastDev/yew-component-size) - A Yew component that emits events when the parent component changes width/height.\n- [yew-virtual-scroller](https://github.com/AircastDev/yew-virtual-scroller) - A Yew component for virtual scrolling / scroll windowing.\n- [yew-autoprops](https://crates.io/crates/yew-autoprops) - proc-macro to automatically derive Properties structs from args for Yew components.\n\n### Hooks\n\n- [yew-hooks](https://github.com/jetli/yew-hooks) - Custom Hooks library for Yew, inspired by [streamich/react-use](https://github.com/streamich/react-use) and [alibaba/hooks](https://github.com/alibaba/hooks).\n- [yew-side-effect](https://github.com/futursolo/yew-side-effect) - Reconcile Side Effects in Yew Applications, inspired by [react-side-effect](https://github.com/gaearon/react-side-effect) and [react-helmet](https://github.com/nfl/react-helmet).\n- [Bounce](https://github.com/futursolo/bounce) - The uncomplicated state management library for Yew, inspired by [Redux](https://github.com/reduxjs/redux) and [Recoil](https://github.com/facebookexperimental/Recoil).\n\n### Utils\n\n- [Yewdux](https://github.com/intendednull/yewdux) - Redux-like state containers for Yew apps.\n- [reacty_yew](https://github.com/hobofan/reacty_yew) - Generate Yew components from React components via Typescript type definitions.\n- [styled-yew](https://github.com/IcyDefiance/styled-yew) - CSS in Rust, similar to styled-components, but for Yew.\n- [stylist-rs](https://github.com/futursolo/stylist-rs) - A CSS-in-Rust styling solution for WebAssembly Applications.\n- [Yew Interop](https://github.com/Madoshakalaka/yew-interop) - Load JavaScript and CSS asynchronously in Yew.\n- [Tailwind RS](https://github.com/oovm/tailwind-rs) - Tailwind style tracer in rust, JIT + AOT interpreter.\n\n### Wasm\n\n- [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) - Facilitating high-level interactions between WebAssembly modules and JavaScript.\n- [stdweb](https://github.com/koute/stdweb) - Provides Rust bindings to the Web APIs and to allow a high degree of interoperability between Rust and JavaScript.\n\n## Tooling\n\n- [wasm-pack](https://github.com/rustwasm/wasm-pack) - Your favorite Rust -> WebAssembly workflow tool.\n- [wasm-pack-action](https://github.com/jetli/wasm-pack-action) - Github action to install `wasm-pack` by downloading the executable to speed up CI/CD.\n- [wasm-bindgen-action](https://github.com/jetli/wasm-bindgen-action) - Github action to install `wasm-bindgen` by downloading the executable to speed up CI/CD.\n- [cargo-web](https://github.com/koute/cargo-web) - A Cargo subcommand for the client-side Web.\n- [Trunk](https://github.com/thedodd/trunk) - Build, bundle & ship your Rust Wasm application to the web.\n- [trunk-action](https://github.com/jetli/trunk-action) - Github action to install `Trunk` by downloading the executable to speed up CI/CD.\n- [wabt](https://github.com/WebAssembly/wabt) - The WebAssembly Binary Toolkit, for the `wasm-strip` and `wasm-objdump` tools to reduce .wasm file size.\n- [binaryen](https://github.com/WebAssembly/binaryen) - Compiler infrastructure and toolchain library for WebAssembly, for the `wasm-opt` tool to reduce .wasm file size.\n\n## Articles\n\n- [Let's Build a Rust Frontend with Yew](https://dev.to/deciduously/lets-build-a-rust-frontend-with-yew---part-1-3k2o)\n- [A Web Application completely in Rust](https://medium.com/@saschagrunert/a-web-application-completely-in-rust-6f6bdb6c4471)\n- [Yew - Rust & WebAsse-frontend framework](https://sudonull.com/post/11627-Yew-Rust-WebAsse-frontend-framework)\n- [Create a desktop app in Rust using Tauri and Yew](https://dev.to/stevepryde/create-a-desktop-app-in-rust-using-tauri-and-yew-2bhe)\n- [A code walkthrough video of Yew with a real-world app with Christopher Hunt and Kiki Carter](https://www.youtube.com/watch?v=ilrGIJGdqRo)\n\n## Books\n\n- [The WebAssembly Book](https://rustwasm.github.io/docs/book/) - Working with the web and producing .wasm files.\n- [The wasm-bindgen Guide](https://wasm-bindgen.github.io/wasm-bindgen/) - How to bind Rust and JavaScript APIs.\n- [The wasm-pack Guide](https://drager.github.io/wasm-pack/book/) - How to build and work with rust-generated WebAssembly.\n- [Programming WebAssembly with Rust](https://pragprog.com/book/khrust/programming-webassembly-with-rust) - Includes a chapter `Advanced JavaScript Integration with Yew` on creating an app with Yew.\n- [Creative Projects for Rust Programmers](https://www.oreilly.com/library/view/creative-projects-for/9781789346220/) - Chapter 5, `Creating a Client-Side WebAssembly App Using Yew`.\n\n## Alternatives\n\nYew team love to share ideas with other projects and believe we can all help each other reach the full potential of this exciting new technology.\n\n- [Draco](https://github.com/utkarshkukreti/draco) - A Rust library for building client side web applications with WebAssembly.\n- [Percy](https://github.com/chinedufn/percy) - A modular toolkit for building isomorphic web apps with Rust + WebAssembly.\n- [Sauron](https://github.com/ivanceras/sauron) - Sauron is an HTML web framework for building web-apps.\n- [Seed](https://github.com/seed-rs/seed) - A Rust framework for creating web apps.\n- [Smithy](https://github.com/rbalicki2/smithy) - A framework for building WebAssembly apps in Rust.\n- [Dioxus](https://github.com/DioxusLabs/dioxus) - Elegant React-like library for building user interfaces for desktop, web, mobile, SSR, liveview, and more.\n- [Sycamore](https://github.com/sycamore-rs/sycamore) - A reactive library for creating web apps in Rust and WebAssembly.\n\n## Related lists\n\n- [Awesome Rust and WebAssembly](https://github.com/rustwasm/awesome-rust-and-webassembly) - A list of awesome Rust and WebAssembly projects, libraries, tools, and resources.\n- [Awesome WebAssembly](https://github.com/mbasso/awesome-wasm) - Collection of awesome things regarding WebAssembly ecosystem.\n- [Awesome Rust](https://github.com/rust-unofficial/awesome-rust) - A curated list of Rust code and resources.\n"
  },
  {
    "path": "website/community/external-libs.mdx",
    "content": "---\ntitle: 'Libraries'\ndescription: 'Libraries that can help with Yew development'\n---\n\n## Malvolio\n\n[Malvolio](https://crates.io/crates/malvolio) is a library with a \"builder-syntax\" for creating complex HTML documents\nwith ease. It runs both on servers (and renders to strings) or in browsers (with Yew).\n\n## Weblog\n\n[weblog](https://crates.io/crates/weblog) is a crate that defines a set of macros for calling `console.log()`,\n`console.error()` and other members of the browser's console API when targeting WASM.\n\n## Gloo\n\n[Gloo](https://crates.io/crates/gloo) is a modular toolkit for building fast, reliable Web applications and\nlibraries with Rust and Wasm. Gloo provides ergonomic Rust APIs for working with:\n\n- [Console timers](https://crates.io/crates/gloo-console-timer)\n- [Dialogs](https://crates.io/crates/gloo-dialogs)\n- [Events](https://crates.io/crates/gloo-events)\n- [Files](https://crates.io/crates/gloo-file)\n- [Requests](https://crates.io/crates/gloo-net)\n- [Timers](https://crates.io/crates/gloo-timers)\n- [Web Storage](https://crates.io/crates/gloo-storage)\n\n## Looking For\n\nLibraries that the ecosystem needs, but doesn't have yet.\n\nBootstrap/MaterialUi/arbitrary css framework component wrappers.\n"
  },
  {
    "path": "website/docs/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! {{for modified_children}}\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/docs/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: 'Low level details about the framework'\n---\n\n# Low-level library internals\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/docs/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/docs/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: 'Optimizations & Best Practices'\nsidebar_label: Optimizations\ndescription: 'Make your app faster'\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nTo avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications, it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component or just a big\nfunction that produces `Html`. Code that is shared between the crates containing different parts of\nthe application could be stored in a separate crate which the project depends on.\nIn the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and additionally render the component you are working on.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther, it is possible to optimize the size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/docs/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## SSR limitation\n\nPortals are **not rendered during server-side rendering**. They require a live\nDOM host element (`web_sys::Element`) which is unavailable on the server.\nIf you need to render content into `<head>` during SSR, see the\n[head rendering section](./server-side-rendering#rendering-head-tags)\nin the SSR documentation.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/docs/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## Rendering `<head>` Tags\n\nA common need with SSR is rendering dynamic `<head>` content (e.g. `<title>`,\n`<meta>`) so that crawlers and social previews see the right metadata on first\nload.\n\n`ServerRenderer` only renders your component tree (typically at the body of the document),\nit has no access to `<head>`. Head tags must therefore be generated **on the server, outside of\nYew**, and spliced into the HTML template before it is sent to the client.\n\nThe [`ssr_router` example](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) demonstrates this pattern: the server recognizes the\nroute from the request URL, generates the appropriate `<title>` and `<meta>`\ntags, and injects them into the Trunk-generated `index.html` before\n`</head>`.\n\n:::info\n\nFor a fully SSR-compatible third-party solution, use [the `<Helmet/>` component from Bounce](https://docs.rs/bounce/latest/bounce/helmet/index.html).\n\n:::\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## Single thread mode\n\nYew supports single thread mode for server-side rendering by `yew::LocalServerRenderer`. This mode would work in a single thread environment like WASI.\n\n```rust\n// Build using `wasm32-wasip1` target or `wasm32-wasip2` target.\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\nExample: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\nIf you are using the `wasm32-unknown-unknown` target to build a SSR application, you can use the `not_browser_env` feature flag to disable access of browser-specific APIs inside of Yew. This would be useful on serverless platforms like Cloudflare Worker.\n:::\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'Lifecycle'\ndescription: 'Components and their lifecycle hooks'\n---\n\nThe `Component` trait has a number of methods which need to be implemented; Yew will call these at different\nstages in the lifecycle of a component.\n\n## Lifecycle\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## Lifecycle Methods\n\n### Create\n\nWhen a component is created, it receives properties from its parent component and is stored within\nthe `Context<Self>` that is passed down to the `create` method. The properties can be used to\ninitialize the component's state and the \"link\" can be used to register callbacks or send messages to the component.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nThe `view` method allows you to describe how a component should be rendered to the DOM. Writing\nHTML-like code using Rust functions can become quite messy, so Yew provides a macro called `html!`\nfor declaring HTML and SVG nodes (as well as attaching attributes and event listeners to them) and a\nconvenient way to render child components. The macro is somewhat similar to React's JSX (the\ndifferences in programming language aside).\nOne difference is that Yew provides a shorthand syntax for properties, similar to Svelte, where instead of writing `onclick={onclick}`, you can just write `{onclick}`.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\nFor usage details, check out [the `html!` guide](concepts/html/introduction.mdx).\n\n### Rendered\n\nThe `rendered` component lifecycle method is called once `view` has been called and Yew has rendered\nthe results to the DOM, but before the browser refreshes the page. This method is useful when you\nwant to perform actions that can only be completed after the component has rendered elements. There\nis also a parameter called `first_render` which can be used to determine whether this function is\nbeing called on the first render, or instead a subsequent one.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nNote that this lifecycle method does not require implementation and will do nothing by default.\n:::\n\n### Update\n\nCommunication with components happens primarily through messages which are handled by the\n`update` lifecycle method. This allows the component to update itself\nbased on what the message was, and determine if it needs to re-render itself. Messages can be sent\nby event listeners, child components, Agents, Services, or Futures.\n\nHere is an example of what an implementation of `update` could look like:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nComponents may be re-rendered by their parents. When this happens, they could receive new properties\nand need to re-render. This design facilitates parent-to-child component communication by just\nchanging the values of a property. There is a default implementation that re-renders the component\nwhen props are changed.\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods but are only caused when trying to update\nthe same component after every render, when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it is often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample, you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to the component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nProperties enable child and parent components to communicate with each other.\nEvery component has an associated properties type which describes what is passed down from the parent.\nIn theory, this can be any type that implements the `Properties` trait, but in practice, there is no\nreason for it to be anything but a struct where each field represents a property.\n\n## Derive macro\n\nInstead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to\nautomatically generate the implementation instead.\nTypes for which you derive `Properties` must also implement `PartialEq`.\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they are set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: 'Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` keyword can be used inside of any HTML element or component to get the DOM `Element` that\nthe item is attached to. This can be used to make changes to the DOM outside of the `view` lifecycle\nmethod.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\nThe syntax is:\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/docs/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/docs/concepts/agents.mdx",
    "content": "---\ntitle: 'Agents'\ndescription: \"Yew's Actor System\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nAgents are a way to offload tasks to web workers.\n\nIn order for agents to run concurrently, Yew uses\n[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).\n\n## Lifecycle\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## Types of Agents\n\n### Reaches\n\n- Public - There will exist at most one instance of a Public Agent at any given time. Bridges will\n  spawn or connect to an already spawned agent in a web worker.\n  When no bridges are connected to this agent, the agent will disappear.\n\n- Private - Spawn a new agent in a web worker for every new bridge. This is good for moving shared but\n  independent behavior that communicates with the browser out of components. When\n  the connected bridge is dropped, the agent will disappear.\n\n- Global \\(WIP\\)\n\n## Communication between Agents and Components\n\n### Bridges\n\nA bridge allows bi-directional communication between an agent and a component. Bridges also allow agents to communicate with one another.\n\nA `use_bridge` hook is also provided to create bridges in a function component.\n\n### Dispatchers\n\nA dispatcher allows uni-directional communication between a component and an agent. A dispatcher allows a component to send messages to an agent.\n\n## Overhead\n\nAgents use web workers \\(i.e. Private and Public\\). They incur a serialization overhead on the\nmessages they send and receive. Agents use [bincode](https://github.com/bincode-org/bincode) to communicate\nwith other threads, so the cost is substantially higher than just calling a function.\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) example shows how\n  components can send messages to and receive messages from agents.\n"
  },
  {
    "path": "website/docs/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'CSS with classes!'\ndescription: 'A handy macro to handle classes'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew does not natively provide a CSS-in-Rust solution but helps with styling by providing\nprogrammatic ways to interact with the HTML `class` attribute.\n\n## `classes!` macro\n\nThe `classes!` macro and associated `Classes` struct simplify the use of HTML classes:\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\nWe will expand upon this concept in [more CSS](../../more/css).\n\n## Inline Styles\n\nCurrently Yew does not provide any special help with inline styles specified via the `style` attribute,\nbut you can use it like any other HTML attribute:\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\nWe will expand upon this concept in [more CSS](../../more/css).\n"
  },
  {
    "path": "website/docs/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'HTML with html!'\ndescription: 'It is HTML but not quite!'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYou can write expressions resembling HTML with the `html!` macro. Behind the scenes, Yew turns\nit into rust code representing the DOM to generate.\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nSimilar to format expressions, there is an easy way to embed values from the surrounding\ncontext into the HTML by applying curly brackets:\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\nOne major rule comes with the use of `html!` - you can only return 1 wrapping node.\nTo render a list of multiple elements, `html!` allows fragments. Fragments are tags\nwithout a name, that produce no HTML element by themselves.\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// error: only one root HTML element allowed\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// fixed: using HTML fragments\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\nWe will introduce Yew and HTML further in depth in [more HTML](concepts/html/introduction.mdx).\n"
  },
  {
    "path": "website/docs/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JS with RS'\ndescription: 'JavaScript with Rust'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files, while also keeping the underlying technology\n> accessible where necessary.\n\nAs of today, WebAssembly is not feature-complete for DOM interactions. This means even in Yew we\nsometimes rely on calling JavaScript. What follows is an overview of the involved libraries.\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool that bridges calls between JavaScript and Rust functions.\n\nWe highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./wasm-bindgen.mdx).\n\n## web-sys\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs and allows us to write JavaScript code in a rustyfied and safe way.\n\nExample:\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\nOnce again we highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./web-sys.mdx).\n"
  },
  {
    "path": "website/docs/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool to facilitate\nhigh-level interactions between Wasm modules and JavaScript; it is built with Rust by\n[The Rust and WebAssembly Working Group](https://rustwasm.github.io/).\n\nYew uses `wasm-bindgen` to interact with the browser through a number of crates:\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nThis section will explore some of these crates at a high level, to make it easier to understand\nand use `wasm-bindgen` APIs with Yew. For a more in-depth guide to `wasm-bindgen` and its associated\ncrates then check out [The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/).\n\nFor documentation on the above crates check out [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html).\n\n:::tip\nUse the `wasm-bindgen` doc.rs search to find browser APIs and JavaScript types that have been imported\nover using `wasm-bindgen`.\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nThis crate provides many of the building blocks for the rest of the crates above. In this section we\nare only going to cover two main areas of the `wasm-bindgen` crate and that is the macro and some\ntypes/traits you will see pop up again and again.\n\n### `#[wasm_bindgen]` macro\n\nThe `#[wasm_bindgen]` macro provides an interface between Rust and JavaScript, providing a system\nfor translating between the two. Using this macro is more advanced, and you should not need to reach\nfor it unless you are trying to use an external JavaScript library. The `js-sys` and `web-sys`\ncrates expose `wasm-bindgen` definitions for built-in JavaScript types and browser APIs.\n\nLet's go over a simple example of using the `#[wasm-bindgen]` macro to import some specific flavours\nof the [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) function.\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// First up let's take a look of binding `console.log` manually, without the\n// help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations\n// manually ourselves, and the correctness of our program relies on the\n// correctness of these annotations!\n#[wasm_bindgen]\nextern \"C\" {\n    // Use `js_namespace` here to bind `console.log(..)` instead of just\n    // `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // The `console.log` is quite polymorphic, so we can bind it with multiple\n    // signatures. Note that we need to use `js_name` to ensure we always call\n    // `log` in JS.\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // Multiple arguments too!\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// using the imported functions!\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_This example was adapted from [1.2 Using console.log of The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html)_.\n\n### Simulating inheritance\n\nInheritance between JavaScript classes is a core feature of the Javascript language and the DOM\n(Document Object Model) is designed around it. When types are imported using `wasm-bindgen` you can\nalso add attributes that describe their inheritance.\n\nIn Rust, this inheritance is represented using the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\nand [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) traits. An example of this\nmight help; so say you have three types `A`, `B`, and `C` where `C` extends `B` which in turn\nextends `A`.\n\nWhen importing these types the `#[wasm-bindgen]` macro will implement the `Deref` and `AsRef`\ntraits in the following way:\n\n- `C` can `Deref` to `B`\n- `B` can `Deref` to `A`\n- `C` can be `AsRef` to `B`\n- Both `C` & `B` can be `AsRef` to `A`\n\nThese implementations allow you to call a method from `A` on an instance of `C` and to use `C` as if\nit was `&B` or `&A`.\n\nIt is important to note that every single type imported using `#[wasm-bindgen]` has the same root type,\nyou can think of it as the `A` in the example above, this type is [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) which has\nits section below.\n\n_[extends section in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\nThis is a representation of an object owned by JavaScript, this is a root catch-all type for `wasm-bindgen`.\nBecause JavaScript does not have a strong type system, any type that comes from `wasm-bindgen` is a `JsValue`.\nFunctions in JavaScript do not define the type of any variables they take in or return; variables can be\nany valid JavaScript value, hence `JsValue`. If you are working with imported functions or types that\naccept a `JsValue`, then any imported value is _technically_ valid.\n\nEven though `JsValue` may be accepted by a JS function, that function may still only _actually_ accept certain types.\nPassing an incorrect `JsValue` can lead to an exception which triggers a panic - so when using raw `wasm-bindgen` APIs,\ncheck the your JavaScript's documentation for types of inputs that will cause an exception (and a panic).\n\n_[`JsValue` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)._\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust has a strong type system and JavaScript...doesn't 😞. For Rust to maintain these\nstrong types but still be convenient, the WebAssembly group came up with a pretty neat trait `JsCast`.\nIts job is to help you move from one JavaScript \"type\" to another, which sounds vague, but it means\nthat if you have one type which you know is another, then you can use the functions of `JsCast`\nto jump from one type to the other. It is a nice trait to get to know when working with `web-sys`,\n`wasm_bindgen`, `js-sys` - you will notice lots of types will implement `JsCast` from those crates.\n\n`JsCast` provides both checked and unchecked methods of casting - so if at runtime if you are\nunsure what type a certain object is, you can try to cast it, which returns possible failure types like\n[`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) and\n[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).\n\nA common example of this in [`web-sys`](./web-sys.mdx) is when you are trying to get the\ntarget of an event. You might know what the target element is, but the\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API will always return an [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target).\nYou will need to cast it to the element type so you can call its methods.\n\n```rust\n// need to import the trait.\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // maybe the target is a select element?\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // do something amazing here\n        return;\n    }\n\n    // if it wasn't a select element then I KNOW it's a input element!\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\nThe [`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref)\nmethod is a checked cast that returns an `Option<&T>`, which means the original type\ncan be used again if the cast failed and thus returned `None`. The\n[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nmethod will consume `self`, as per convention for `into` methods in Rust, and the type returned is\n`Result<T, Self>`. If the casting fails, the original `Self` value is returned in `Err`. You can try again\nor do something else with the original type.\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\nThe `Closure` type provides a way to transfer Rust closures to JavaScript. The closures passed to\nJavaScript must have a `'static` lifetime for soundness reasons.\n\nThis type is a \"handle\" in the sense that whenever it is dropped, it will invalidate the JS\nclosure that it refers to. Any usage of the closure in JS after the Closure has been dropped will\nraise an exception.\n\n`Closure` is often used when you are working with a `js-sys` or `web-sys` API that accepts a type\n[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html).\nAn example of using a `Closure` in Yew can be found in the [Using `Closure` section](../html/events.mdx#using-closure-verbose)\non the [Events](../html/events.mdx) page.\n\n_[`Closure` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\nThe `js-sys` crate provides bindings/imports of JavaScript's standard, built-in objects, including\ntheir methods and properties.\n\nThis does not include any web APIs; that's what [`web-sys`](./web-sys.mdx) is for!\n\n_[`js-sys` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\nThe `wasm-bindgen-futures` crate provides a bridge for working with JavaScript Promise types as a\nRust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html), and contains\nutilities to turn a rust Future into a JavaScript Promise. This can be useful when working with\nasynchronous or otherwise blocking work in Rust (wasm), and provides the ability to interoperate\nwith JavaScript events and JavaScript I/O primitives.\n\nThere are three main interfaces in this crate currently:\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   A type that is constructed with a [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html)\n   and can then be used as a `Future<Output=Result<JsValue, JsValue>>`. This `Future` will resolve to `Ok` if\n   the `Promise` is resolved and `Err` if the `Promise` is rejected, containing the resolved or rejected\n   value from the `Promise` respectively.\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Converts a Rust `Future<Output=Result<JsValue, JsValue>>` into a\n   JavaScript `Promise`. The future’s result will translate to either a resolved or rejected\n   `Promise` in JavaScript.\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   Spawns a `Future<Output = ()>` on the current thread. This is the best way\n   to run a Future in Rust without sending it to JavaScript.\n\n_[`wasm-bindgen-futures` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` is going to be the most commonly used part of the `wasm-bindgen-futures` crate in Yew\nas this helps when using libraries that have async APIs.\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // console log \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew has also added support for futures in certain APIs, most notably you can create a\n`callback_future` which accepts an `async` block - this uses `spawn_local` internally.\n\n_[`spawn_local` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/docs/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'The web-sys crate provides bindings for Web APIs.'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs. This is\nprocedurally generated from browser WebIDL which is why some names are so long and why some types are vague.\n\n## Features in `web-sys`\n\nThe `web-sys` crate with all of its features enabled can add lots of bloat to a Wasm application.\nTo get around this issue most types are feature gated so that you only include the types\nyou require for your application. Yew enables several features from `web-sys` and\nexposes some types in its public API. You will often need to add `web-sys` as a dependency yourself.\n\n## Inheritance in `web-sys`\n\nIn the [Simulating inheritance section](./wasm-bindgen.mdx#simulating-inheritance) you can read how in\ngeneral Rust provides an approach to simulate inheritance in JavaScript. This is very important in\n`web-sys` as understanding what methods are available on a type means understanding its inheritance.\n\nThis section is going to look at a specific element and list out its inheritance using Rust by\ncalling [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) until\nthe value is [`JsValue`](./wasm-bindgen.mdx#jsvalue):\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement is <textarea> in html.\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // Notice we have moved from web-sys types now into built-in\n    // JavaScript types which are in the js-sys crate.\n    let object: &js_sys::Object = event_target.deref();\n\n    // Notice we have moved from js-sys type to the root JsValue from\n    // the wasm-bindgen crate.\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // Using deref like this means we have to manually traverse\n    // the inheritance tree, however, you can call JsValue methods\n    // on the HtmlTextAreaElement type.\n    // The `is_string` method comes from JsValue.\n    assert!(!text_area.is_string());\n\n    // empty function just to prove we can pass HtmlTextAreaElement as a\n    // &EventTarget.\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // The compiler will walk down the deref chain in order to match the types here.\n    this_function_only_takes_event_targets(&text_area);\n\n    // The AsRef implementations allow you to treat the HtmlTextAreaElement\n    // as an &EventTarget.\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[Inheritance in `web-sys` in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)._\n\n## The `Node` in `NodeRef`\n\nYew uses a [`NodeRef`](concepts/function-components/node-refs.mdx) to provide a way for keeping a reference to\na `Node` made by the [`html!`](concepts/html/introduction.mdx) macro. The `Node` part of `NodeRef` is referring to\n[`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html). The\n`NodeRef::get` method will return a `Option<Node>` value, however, most of the time in Yew you want\nto cast this value to a specific element so you can use its specific methods. This casting\ncan be done using [`JsCast`](./wasm-bindgen.mdx#JsCast) on the `Node` value, if present, but Yew\nprovides the `NodeRef::cast` method to perform this casting for convenience and so that you do not\nnecessarily have to include the `wasm-bindgen` dependency for the `JsCast` trait.\n\nThe two code blocks below do essentially the same thing, the first is using `NodeRef::cast` and\nthe second is using [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\non the `web_sys::Node` returned from `NodeRef::get`.\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript example to Rust\n\nThis section demonstrates examples of how JavaScript code which interact with the\nWeb APIs can be rewritten with `web-sys` in Rust.\n\n### JavaScript example\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e = Mouse event.\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left //x position within the element.\n    var y = e.clientY - rect.top //y position within the element.\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` example\n\nUsing `web-sys` alone the above JavaScript example could be implemented like this:\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable all the web-sys features we want to use!\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e: MouseEvent| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// we now need to save the `mousemove` Closure so that when\n// this event fires the closure is still in memory.\n```\n\nThis version is much more verbose, but you will probably notice part of that is because of failure\ntypes reminding us that some of these function calls have invariants that must be held, or otherwise will\ncause a panic in Rust. Another part of the verbosity is the calls to `JsCast` to cast into\ndifferent types so that you can call its specific methods.\n\n### Yew example\n\nIn Yew you will mostly be creating [`Callback`](concepts/function-components/callbacks.mdx)s to use in the\n[`html!`](concepts/html/introduction.mdx) macro so the example is going to use this approach instead of completely copying\nthe approach above:\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable the `DomRect` feature to use the\n# `get_bounding_client_rect` method.\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## External libraries\n\n`web-sys` is a raw binding to the Web API so it comes with some pain in Rust because it was not\ndesigned with Rust or even a strong type system in mind, this is where community crates\nprovide abstractions over `web-sys` to provide more idiomatic Rust APIs.\n\n_[External libraries page](/community/external-libs)_\n"
  },
  {
    "path": "website/docs/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/docs/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\nCallbacks are used to asynchronously communicate upwards the components tree and with other things like agents or the DOM during event handling.\nInternally their type is just an `Fn` wrapped in `Rc` to allow them to be cheaply cloned.\n\nThey have an `emit` function if you want to call them manually.\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\")); // call the callback\n// web_sys::console::log_1(&result.into()); // if uncommented will print \"Bye Bob\"\n```\n\n## Passing callbacks as props\n\nA common pattern in yew is to create a callback and pass it down as a prop.\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// Then supply the prop\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM Events and Callbacks\n\nCallbacks are also used to hook into DOM events.\n\nFor example, here we define a callback that will be called when the user clicks the button:\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/docs/concepts/function-components/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // the field name `children` is important!\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n    // highlight-next-line\n            { props.children.clone() } // you can forward children like this\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/docs/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'Communication between components'\n---\n\n## Parent to child messaging\n\nPass data as [props](./properties) that cause a re-render, this is the way to pass messages to children.\n\n## Child to parent messaging\n\nPass down a callback via props, that the child on an event can call. [Example](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/docs/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'Generic Components'\ndescription: 'The #[component] attribute'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `#[component]` attribute also works with generic functions for creating generic components.\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// then can be used like this\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// or\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/docs/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'Custom Hooks'\n---\n\n## Defining custom Hooks\n\nThe stateful logic of a component can be extracted into reusable functions by creating custom Hooks.\n\nConsider that we wish to create an event listener that listens to an event on the `window`\nobject.\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nThere's one problem with this code: the logic can't be reused by another component.\nIf we build another component that listens to a different event,\ninstead of copying the code, we can move the logic into a custom hook.\n\nWe'll start by creating a new function called `use_event`.\nThe `use_` prefix denotes that a function is a hook.\nThis function will take an event target, an event type, and a callback.\nAll hooks must be marked by `#[hook]` on their function definition.\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nThis simple hook can be created by composing built-in hooks. For this example, we'll use the\n`use_effect_with` hook, so an event listener can be recreated when the hook arguments change.\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nAlthough this approach works in almost all cases, it can't be used to write primitive hooks like the pre-defined hooks we've been using already.\n\nView the docs on [docs.rs](https://docs.rs/yew) for documentation and `hooks` directory to see implementations of pre-defined hooks.\n"
  },
  {
    "path": "website/docs/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks are functions that let you store state and perform side effects.\n\nYew comes with a few pre-defined hooks. You can also create your own or discover many [community-made hooks](/community/awesome#hooks).\n\n## Rules of hooks\n\n1. A hook function name always has to start with `use_`\n2. Hooks can only be used in the following locations:\n    - Top-level of a function/hook.\n    - Blocks inside a function/hook, given it is not already branched.\n    - In the condition of a top-level `if` expression inside a function/hook.\n    - In the scrutinee of a top-level `match` expression inside a function/hook.\n3. Hooks must be called in the same order for every render. Returning early is only allowed when using [Suspense](../../suspense.mdx)\n\nThese rules are enforced by either compile-time or run-time errors.\n\n### Pre-defined Hooks\n\nYew comes with the following predefined Hooks:\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nThe documentation for these hooks can be found in the [Yew API docs](https://yew-rs-api.web.app/next/yew/functional/)\n\n### Custom Hooks\n\nThere are cases where you want to define your own Hooks to encapsulate potentially stateful logic from a component into reusable functions.\nSee the [Defining custom hooks](concepts/function-components/hooks/custom-hooks.mdx#defining-custom-hooks) section for more information.\n\n## Further reading\n\n- The React documentation has a section on [React hooks](https://reactjs.org/docs/hooks-intro.html).\n  These are not the same as Yew's hooks, but the underlying concept is similar.\n"
  },
  {
    "path": "website/docs/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/docs/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'Node Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` attribute can be used to attach the `NodeRef` to an HTML element. In callbacks,\nyou can then get the DOM `Element` that the ref is attached to. This can be used to make\nchanges to the DOM outside of the `view` lifecycle method, retrieve the value of an `<input>`\nand other direct interactions with the DOM via the javascript API.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\n\n:::caution\nDo not manually modify the DOM tree that is rendered by Yew. Treat the `NodeRef` as a read-only\naccess, if you are unsure.\n:::\n\n## Further Reading\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` example](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/docs/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nProperties are often shortened as \"Props\".\n\n:::\n\nProperties are essentially component arguments that Yew can keep watch on.\n\nA type has to implement the `Properties` trait before it can be used as the properties of a component.\n\n## Reactivity\n\nYew checks if props have changed when reconciling the Virtual DOM during re-rendering, to know if nested components need to be re-rendered.\nThis way Yew can be considered a very reactive framework, as changes from the parent will always be propagated downward,\nand the view will never be out of sync with the data coming from props/state.\n\n:::tip\n\nIf you have not yet completed the [tutorial](../../tutorial), try it out and test this reactivity yourself!\n\n:::\n\n## Derive macro\n\nYew provides a derive macro to easily implement the `Properties` trait on structs.\n\nTypes for which you derive `Properties` must also implement `PartialEq` so Yew can do data comparison.\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## Use in function components\n\nThe attribute `#[component]` allows to optionally receive Props in the function arguments. To supply them,\nthey are assigned via attributes in the `html!` macro.\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// Then supply the prop\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// No props to supply\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## Derive macro field attributes\n\nWhen deriving `Properties` all fields are required by default.\nThe following attributes allow you to give your props default values which will be used when the parent has not set them.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`. The expression\nis evaluated when the properties are constructed and no explicit value has been given.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\nThe function is called when no explicit value has been given for that attribute.\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a shared pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // Notice we did not need to specify name prop\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## Automatically generate properties (yew-autoprops)\n\nIn order to streamline your development process, you can also use the macro\n`#[autoprops]` (from the crate `yew-autoprops`) that will automatically\ngenerate the `Properties` struct for you.\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// the #[autoprops] macro must appear BEFORE #[component], the order matters\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// The properties struct \"GreetingsProps\" will be generated automatically.\n//\n// `is_loading` will be passed as value to the components while `message` and\n// `name` will use references because of the leading `&` in the definition.\n```\n\n## Evaluation Order\n\nProps are evaluated in the order they're specified, as shown by the following example:\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nlet mut g = 1..=3;\nlet props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\nassert_eq!(props.first, 1);\nassert_eq!(props.second, 2);\nassert_eq!(props.last, 3);\n```\n\n## Anti Patterns\n\nWhile almost any Rust type can be passed as properties, there are some anti-patterns that should be avoided.\nThese include, but are not limited to:\n\n1. Using `String` type instead of `AttrValue`. <br />\n   **Why is this bad?** `String` can be expensive to clone.\n   Cloning is often needed when the prop value is used with hooks and callbacks. `AttrValue` is either\n   a reference-counted string (`Rc<str>`) or a `&'static str`, thus very cheap to clone.<br />\n   **Note**: `AttrValue` internally is `IString` from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n2. Using interior mutability. <br />\n   **Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should\n   _generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when the state has changed)\n   so you may have to manually force a render. Like all things, it has its place. Use it with caution.\n3. Using `Vec<T>` type instead of `IArray<T>`. <br />\n   **Why is this bad?** `Vec<T>`, just like `String`, can also be expensive to clone. `IArray<T>` is either\n   a reference-counted slice (`Rc<[T]>`) or a `&'static [T]`, thus very cheap to clone.<br />\n   **Note**: `IArray` can be imported from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n4. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue\n   or PR a fix to this documentation.\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) is an experimental package that allows one to create the Props struct on the fly out of the arguments of your function. Might be useful, if the properties struct is never reused.\n"
  },
  {
    "path": "website/docs/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: 'Pure Components'\n---\n\nA function component is considered [pure] when the returned `Html` is deterministically derived\nfrom its props when its view function does not mutate its state or has other side effects.\n\n[pure]: https://en.wikipedia.org/wiki/Pure_function\n\nThe example below is a pure component. For a given prop `is_loading` it will always result in the same `Html` without any side effects.\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\nIf you have an internal pure component that makes no use of hooks and other component machinery, you can often write it instead\nas a normal function returning `Html` and avoid a bit of overhead for Yew, related to running the component lifecycle. Use\n[expression syntax](concepts/html/literals-and-expressions.mdx#expressions) to render them in `html!`.\n:::\n\n## Impure components\n\nYou might wonder if a component can be impure if it does not use any globals, since it is just a function that is called every render.\nThis is where the next topic comes in - [hooks](./hooks)\n"
  },
  {
    "path": "website/docs/concepts/function-components/state.mdx",
    "content": "---\ntitle: 'State'\n---\n\n## General view of how to store state\n\nThis table can be used as a guide when deciding what state-storing type fits best for your use case:\n\n| Hook                     | Type                       | Rerender when?               | Scope               |\n| ------------------------ | -------------------------- | ---------------------------- | ------------------- |\n| [use_state]              | `T`                        | got set                      | component instance  |\n| [use_state_eq]           | `T: PartialEq`             | got set with diff. value     | component instance  |\n| [use_reducer]            | `T: Reducible`             | got reduced                  | component instance  |\n| [use_reducer_eq]         | `T: Reducible + PartialEq` | got reduced with diff. value | component instance  |\n| [use_memo]               | `Deps -> T`                | dependencies changed         | component instance  |\n| [use_callback]           | `Deps -> Callback<E>`      | dependencies changed         | component instance  |\n| [use_mut_ref]            | `T`                        | -                            | component instance  |\n| a static global variable | `T`                        | -                            | global, used by all |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/docs/concepts/html/classes.mdx",
    "content": "---\ntitle: 'Classes'\ndescription: 'A handy macro to handle classes'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Classes\n\nThe struct `Classes` can be used to deal with HTML classes.\n\nWhen pushing a string to the set, `Classes` ensures that there is one element\nfor every class even if a single string might contain multiple classes.\n\n`Classes` can also be merged by using `Extend` (i.e.\n`classes1.extend(classes2)`) or `push()` (i.e. `classes1.push(classes2)`).\nAny type that implements `Into<Classes>` can be pushed onto an existing `Classes`.\n\nThe macro `classes!` is a convenient macro that creates one single `Classes`.\nIts input accepts a comma-separated list of expressions. The only requirement\nis that every expression implements `Into<Classes>`.\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Components that accept classes\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/docs/concepts/html/components.mdx",
    "content": "---\ntitle: 'Components'\ndescription: 'Create complex layouts with component hierarchies'\n---\n\n## Basic\n\nComponents can be used in the `html!` macro:\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // With the whole set of props provided at once\n        <MyComponentWithProps ..props.clone() />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## Nested\n\nComponents can accept child components/elements if they have a `children` field in their `Properties`\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\nThe `html!` macro allows you to pass a base expression with the `..props` syntax instead of specifying each property individually,\nsimilar to Rust's [Functional Update Syntax](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax).\nThis base expression must occur after any individual props are passed.\nWhen passing a base props expression with a `children` field, the children passed in the `html!` macro overwrite the ones already present in the props.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // props.children will be overwritten with this\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## Relevant examples\n\n- [Function Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [Function Router](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/docs/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: 'Conditional rendering'\ndescription: 'Rendering nodes conditionally in html!'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If blocks\n\nTo conditionally render some markup, we wrap it in an `if` block:\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/docs/concepts/html/elements.mdx",
    "content": "---\ntitle: 'Elements'\ndescription: 'Both HTML and SVG elements are supported'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM nodes\n\nThere are many reasons why you might want to create or manage DOM nodes manually in Yew, such as\nwhen integrating with JS libraries that can cause conflicts with managed components.\n\nUsing `web-sys`, you can create DOM elements and convert them into a `Node` - which can then be\nused as an `Html` value using `VRef`:\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // memoize as this only needs to be executed once\n    let node = use_memo(\n        (),\n        |_| {\n            // Create a div element from the document\n            let div: Element = document().create_element(\"div\").unwrap();\n            // Add content, classes etc.\n            div.set_inner_html(\"Hello, World!\");\n            // Convert Element into a Node\n            let node: Node = div.into();\n            // Return that Node as a Html value\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo return Rc so we need to deref and clone\n    (*node).clone()\n}\n\n```\n\n## Dynamic tag names\n\nWhen building a higher-order component you might find yourself in a situation where the element's tag name is not static.\nFor example, you might have a `Title` component that can render anything from `h1` to `h6` depending on a level prop.\nInstead of having to use a big match expression, Yew allows you to set the tag name dynamically\nusing `@{name}` where `name` can be any expression that returns a string.\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## Boolean Attributes\n\nSome content attributes (e.g checked, hidden, required) are called boolean attributes. In Yew,\nboolean attributes need to be set to a bool value:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nThis will result in **HTML** that is functionally equivalent to this:\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\nSetting a boolean attribute to false is equivalent to not using the attribute at all; values from\nboolean expressions can be used:\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nThis will result in the following **HTML**:\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## String-like attributes\n\nBut apart from a select few boolean attributes, you will probably be dealing with a lot of string-like HTML attributes and Yew has a few options to pass string-like values to components.\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nThey are all valid **but** we encourage you to favor Yew's custom `AttrValue`, especially if you need to clone or pass them as properties to another component.\n\n## Optional attributes for HTML elements\n\nMost HTML attributes can use optional values (Some(x) or None). This allows us to omit the attribute if the attribute is marked as optional.\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\nIf the attribute is set to `None`, the attribute will not be set in the DOM.\n\n## Children\n\nMost HTML elements accept arbitrary HTML as children, however, there is a set of them that doesn't accept any children at all.\nThese elements are called _void_ elements, and they are:\n\n- `<area />`\n- `<base />`\n- `<base />`\n- `<br />`\n- `<col />`\n- `<embed />`\n- `<hr />`\n- `<img />`\n- `<input />`\n- `<link />`\n- `<meta />`\n- `<param />`\n- `<source />`\n- `<track />`\n- `<wbr />`\n- `<textarea />`\n\nAttempting to provide children to these elements will result in a compilation error or, if the element tag is chosen dynamically, in a panic.\n\n### The case of `<textarea>`\n\nThe `<textarea>` element is special; The modern HTML specification states that children of `<textarea>` define its default value, however in Yew it's specified differently.\nInstead of writing\n\n```html\n<textarea>{\"default value\"}</textarea>\n```\n\nWhich would fail to compile, it's customary to write\n\n```html\n<textarea defaultvalue=\"default value\" />\n```\n\n## Relevant examples\n\n- [Inner HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/docs/concepts/html/events.mdx",
    "content": "---\ntitle: 'Events'\n---\n\n## Introduction\n\nYew integrates with the [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate and\nuses the events from that crate. The [table below](#event-types) lists all of the `web-sys`\nevents that are accepted in the `html!` macro.\n\nYou can still add a [`Callback`](../function-components/callbacks.mdx) for an event that is not listed in the table\nbelow, see [Manual event listener](#manual-event-listener).\n\n## Event Types\n\n:::tip\nAll the event types mentioned in the following table are re-exported under `yew::events`.\nUsing the types from `yew::events` makes it easier to ensure version compatibility than\nif you were to manually include `web-sys` as a dependency in your crate because you will not\nend up using a version which conflicts with the version that Yew specifies.\n:::\n\nThe event listener name is the expected name when adding an event `Callback` in the `html` macro:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nThe event name is the listener without the \"on\" prefix, therefore, the `onclick` event listener\nlistens for `click` events. See the end of this page for a [full list of available event](#available-events) with their types.\n\n## Event bubbling {#event-bubbling}\n\nEvents dispatched by Yew follow the virtual DOM hierarchy when bubbling up to listeners. Currently, only the bubbling phase\nis supported for listeners. Note that the virtual DOM hierarchy is most often, but not always, identical to the actual\nDOM hierarchy. The distinction is important when working with [portals](../../advanced-topics/portals) and other\nmore advanced techniques. The intuition for well-implemented components should be that events bubble from children\nto parents. In this way the hierarchy in your coded `html!` is the one observed by event handlers.\n\nIf you are not interested in event bubbling, you can turn it off by calling\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n_before_ starting your app. This speeds up event handling, but some components may break from not receiving the events they expect.\nUse this with care!\n\n## Event delegation\n\nIt can be surprising that event listeners are _not_ directly registered on the element where they are rendered. Instead, events\nare delegated from the subtree root of the Yew app. Still, events are delivered in their native form, and no synthetic\nform is created. This can lead to mismatches between the event you would expect in HTML listeners and those showing up in Yew.\n\n- [`Event::current_target`] points to the Yew subtree root instead of the element the listener is added on. Use\n  [`NodeRef`](../function-components/node-refs.mdx) if you want access to the underlying `HtmlElement`.\n- [`Event::event_phase`] is always [`Event::CAPTURING_PHASE`]. Internally, the event will behave as if it was in the bubbling\n  phase, the event propagation is replayed and the event [bubbles _up_](#event-bubbling), i.e. event listeners higher up in\n  the virtual DOM will trigger _after_ event listeners below them. Currently, capturing listeners is not supported by Yew.\n\n    This also means that events registered by Yew will usually fire before other event listeners.\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## Typed event target\n\n:::caution\nIn this section **target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))**\nis always referring to the element at which the event was dispatched from.\n\nThis will **not** always be the element at which the `Callback` is placed.\n:::\n\nIn event `Callback`s you may want to get the target of that event. For example, the\n`change` event gives no information but is used to notify that something has changed.\n\nIn Yew getting the target element in the correct type can be done in a few ways and we will go through\nthem here. Calling [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)\non an event returns an optional [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html)\ntype, which might not seem very useful when you want to know the value of your input element.\n\nIn all the approaches below we are going to tackle the same problem, so it is clear where the approach\ndiffers as opposed to the problem at hand.\n\n**The Problem:**\n\nWe have an `onchange` `Callback` on my `<input>` element and each time it is invoked we want to send\nan [update](components#update) `Msg` to our component.\n\nOur `Msg` enum looks like this:\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### Using `JsCast`\n\nThe [`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate has\na useful trait: [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html),\nwhich allows us to hop and skip our way to the type we want, as long as it implements `JsCast`. We can\ndo this cautiously, which involves some runtime checks and failure types like `Option` and `Result`,\nor we can do it dangerously.\n\nEnough talk, more code:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# need wasm-bindgen for JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // When events are created the target is undefined, it's only\n            // when dispatched does the target get added.\n            let target: Option<EventTarget> = e.target();\n            // Events can bubble so this listener might catch events from child\n            // elements which are not of type HtmlInputElement\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        // Here we are sure that this is input element so we can convert it to the appropriate type without checking\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nThe methods from `JsCast` are [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nand [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)\nand you can probably see, they allowed\nus to go from `EventTarget` to [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html).\nThe `dyn_into` method is cautious because at\nruntime it will check whether the type is actually a `HtmlInputElement` and if not return an\n`Err(JsValue)`, the [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\nis a catch-all type and is essentially giving you back the object to try again.\n\nAt this point you might be thinking... when is the dangerous version ok to use? In the case above it\nis safe<sup>1</sup> as we've set the `Callback` on to an element with no children so the target can\nonly be that same element.\n\n_<sup>1</sup> As safe as anything can be when JS land is involved._\n\n### Using `TargetCast`\n\n**It is highly recommended to read [Using JsCast](#using-jscast) first!**\n\n:::note\n`TargetCast` was designed to feel very similar to `JsCast` - this is to allow new users to get a feel\nfor the behaviour of `JsCast` but with the smaller scope of events and their targets.\n\n`TargetCast` vs `JsCast` is purely preference, you will find that `TargetCast` implements something\nsimilar to what you would using `JsCast`.\n:::\n\nThe `TargetCast` trait is built on top of `JsCast` and is specialized towards getting typed event\ntargets from events.\n\n`TargetCast` comes with Yew so no need to add a dependency in order to use the trait methods on events\nbut it works in a very similar way to `JsCast`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nIf you followed the advice above and read about `JsCast`, or know the trait, you can probably\nsee that `TargetCast::target_dyn_into` feels similar to `JsCast::dyn_into` but specifically\ndoes the cast on the target of the event. `TargetCast::target_unchecked_into` is similar to\n`JsCast::unchecked_into`, and as such all the same warnings above `JsCast` apply to `TargetCast`.\n\n### Using `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) can be used instead of querying the event given to a `Callback`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nUsing `NodeRef`, you can ignore the event and use the `NodeRef::cast` method to get an\n`Option<HtmlInputElement>` - this is optional as calling `cast` before the `NodeRef` has been\nset, or when the type doesn't match will return `None`.\n\nYou might also see by using `NodeRef` we don't have to send the `String` back into state as we always access to `input_node_ref` - so we could do the following:\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // do something with value\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nWhich approach you take depends on your component and your preferences, there is no _blessed_ way\nper se.\n\n## Manual event listener\n\nYou may want to listen to an event that is not supported by Yew's `html` macro, see the\n[supported events listed here](#event-types).\n\nIn order to add an event listener to one of elements manually we need the help of\n[`NodeRef`](../function-components/node-refs.mdx) so that in `use_effect_with` we can add a listener using the\n[`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) and\n[wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API.\n\nThe examples below are going to show adding listeners for the made-up `custard` event. All events\neither unsupported by yew or custom can be represented as a\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html). If you\nneed to access a specific method or field on a custom / unsupported event then you can use the\nmethods of [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nin order to convert to the type required.\n\n### Using `Closure` (verbose)\n\nUsing the `web-sys` and `wasm-bindgen` API's directly for this can be a bit painful.. so brace\nyourself ([there is a more concise way thanks to `gloo`](#using-gloo-concise)).\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `Closures`, see\n[The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html).\n\n### Using `gloo` (concise)\n\nThe easier way is with `gloo`, more specifically [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)\nwhich is an abstraction for `web-sys`, `wasm-bindgen`.\n\n`gloo_events` has the `EventListener` type which can be used to create and store the\nevent listener.\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `EventListener`, see the\n[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html).\n\n## Full list of available events {#available-events}\n\n| Event listener name         | `web_sys` Event Type                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/docs/concepts/html/fragments.mdx",
    "content": "---\ntitle: 'Fragments'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro always requires a single root node. To get around this restriction, you\ncan use an \"empty tag\" (these are also called \"fragments\").\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// error: only one root html element allowed\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/docs/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'The procedural macro for generating HTML and SVG'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro allows you to write HTML and SVG code declaratively. It is similar to JSX\n(an extension to JavaScript that allows you to write HTML-like code inside of JavaScript).\n\n**Important notes**\n\n1. The `html!` macro only accepts one root html node (you can counteract this by using\n   [fragments](./fragments.mdx) or [iterators](./../html/lists.mdx))\n2. An empty `html! {}` invocation is valid and will not render anything\n3. Literals must always be quoted and wrapped in braces: `html! { <p>{ \"Hello, World\" }</p> }`\n4. The `html!` macro will make all tag names lowercase. To use upper case characters (which are required for some SVG elements) use [dynamic tag names](concepts/html/elements.mdx#dynamic-tag-names): `html! { <@{\"myTag\"}></@> }`\n\n:::note\nThe `html!` macro can reach the default recursion limit of the compiler. If you encounter compilation errors,\nadd an attribute like `#![recursion_limit=\"1024\"]` in the crate root to overcome the problem.\n:::\n\n## Tag Structure\n\nTags are based on HTML tags. Components, Elements, and Lists are all based on this tag syntax.\n\nTags must either self-close `<... />` or have a corresponding end tag for each start tag.\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\nFor convenience, elements which _usually_ require a closing tag are **allowed** to self-close. For example, writing `html! { <div class=\"placeholder\" /> }` is valid.\n:::\n\n## Children\n\nCreate complex nested HTML and SVG layouts with ease:\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nIf you compile Yew using a nightly version of the Rust compiler, the macro will warn you about some\ncommon pitfalls that you might run into. Of course, you may need to use the stable compiler (e.g.\nyour organization might have a policy mandating it) for release builds, but even if you're using a\nstable toolchain, running `cargo +nightly check` might flag some ways that you could improve your\nHTML code.\n\nAt the moment the lints are mostly accessibility-related. If you have ideas for lints, please feel\nfree to [chime in on this issue](https://github.com/yewstack/yew/issues/1334).\n\n## Specifying attributes and properties\n\nAttributes are set on elements in the same way as in normal HTML:\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\nProperties are specified with `~` before the element name:\n\n```rust , ignore\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\nThe braces around the value can be omitted if the value is a literal.\n\n:::\n\n:::note What classifies as a literal\n\nLiterals are all valid [literal expressions](https://doc.rust-lang.org/reference/expressions/literal-expr.html)\nin Rust. Note that [negative numbers are **not** literals](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)\nand thus must be enclosed in curly-braces `{-6}`\n\n:::\n\n:::note Component properties\nComponent properties are passed as Rust objects and are different from the element attributes/properties described here.\nRead more about them at [Component Properties](../function-components/properties.mdx)\n:::\n\n### Special properties\n\nThere are special properties which don't directly influence the DOM but instead act as instructions to Yew's virtual DOM.\nCurrently, there are two such special props: `ref` and `key`.\n\n`ref` allows you to access and manipulate the underlying DOM node directly. See [Refs](../function-components/node-refs.mdx) for more details.\n\n`key` on the other hand gives an element a unique identifier which Yew can use for optimization purposes.\n\n:::info\nRead more at [Lists](./html/lists)\n:::\n\n## Comments\n\nIt is also possible to use Rust style comments as part of the HTML structure:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <>\n    <h1>{ \"My heading\" }</h1>\n    // here comes the content\n    <main>\n      { \"…\" }\n    </main>\n  </>\n};\n```\n\nComments will be dropped during the parsing process and will not end up in the final output.\n\n## Conditional Rendering\n\nMarkup can be rendered conditionally by using Rust's conditional structures. ' +\n'Currently only `if` and `if let` are supported.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\nRead more at [Conditional Rendering](./conditional-rendering.mdx)\n:::\n"
  },
  {
    "path": "website/docs/concepts/html/lists.mdx",
    "content": "---\ntitle: 'Lists'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Iterators\n\nThere are 3 ways to build HTML from iterators:\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` loops\">\nThe main approach is to use for loops, the same for loops that already exist in Rust, but with 2 key differences:\n1. Unlike standard for loops which can't return anything, for loops in `html!` are converted to a list of nodes;\n2. Diverging expressions, i.e. `break`, `continue` are not allowed in the body of for loops in `html!`.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` block\">\nAn alternative is to use the `for` keyword, which is not native Rust syntax and instead is used by\nthe HTML macro to output the needed code to display the iterator.\nThis approach is better than the first one when the iterator is already computed and the only thing left to do\nis to pass it to the macro.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` method\">\n\nThe last is to call `collect::<Html>()` on the final transform in your iterator, which returns a\nlist that Yew can display.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Keyed lists\n\nA keyed list is an optimized list that has keys on **all** children.\n`key` is a special prop provided by Yew that gives an HTML element or component a unique identifier\nthat is used for optimization purposes inside Yew.\n\n:::caution\nKey has to be unique only in each list, in contrast to the global uniqueness of HTML `id`s. It must not depend on the order of the list.\n:::\n\nIt is always recommended to add keys to lists.\n\nKeys can be added by passing a unique `String`, `str` or integer to the special `key` prop:\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### Performance increases\n\nWe have [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list) example that lets you test the performance improvements, but here is a rough rundown:\n\n1. Go to [Keyed list hosted demo](https://examples.yew.rs/keyed_list)\n2. Add 500 elements.\n3. Disable keys.\n4. Reverse the list.\n5. Look at \"The last rendering took Xms\" (At the time of writing this it was ~60ms)\n6. Enable keys.\n7. Reverse the list.\n8. Look at \"The last rendering took Xms\" (At the time of writing this it was ~30ms)\n\nSo just at the time of writing this, for 500 components it is a 2x increase of speed.\n\n### Detailed explanation\n\nUsually, you just need a key on every list item when you iterate and the order of data can change.\nIt's used to speed up the reconciliation process when re-rendering the list.\n\nWithout keys, assume you iterate through `[\"bob\", \"sam\", \"rob\"]`, ending up with the HTML:\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\nThen on the next render, if your list changed to `[\"bob\", \"rob\"]`, yew could delete\nthe element with id=\"rob\" and update id=\"sam\" to be id=\"rob\"\n\nIf you had added a key to each element, the initial HTML would be the same, but after\nthe render with the modified list, `[\"bob\", \"rob\"]`, yew would just delete the second\nHTML element and leave the rest untouched since it can use the keys to associate them.\n\nIf you ever encounter a bug/\"feature\" where you switch from one component to another but both have a div as the highest rendered element.\nYew reuses the rendered HTML div in those cases as an optimization.\nIf you need that div to be recreated instead of reused, then you can add different keys and they will not be reused.\n\n## Further reading\n\n- [TodoMVC](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/docs/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'Literals and Expressions'\n---\n\n## Literals\n\nIf expressions resolve to types that implement `Display`, they will be converted to strings and inserted into the DOM as a [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) node.\n:::note\nString literals create `Text` nodes, which are treated as strings by the browser. Hence, even if the expression contains a `<script>` tag you can't fall for XSS and such security issues, unless of course you wrap the expression in a `<script>` block.\n:::\n\nAll display text must be enclosed by `{}` blocks because the text is handled as an expression. This is\nthe largest deviation from normal HTML syntax that Yew makes.\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## Expressions\n\nYou can insert expressions in your HTML using `{}` blocks, as long as they resolve to `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\nIt often makes sense to extract these expressions into functions or closures to optimize for readability:\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/docs/concepts/router.mdx",
    "content": "---\ntitle: 'Router'\ndescription: \"Yew's official router\"\n---\n\nRouters in Single Page Applications (SPA) handle displaying different pages depending on what the URL is. Instead of the\ndefault behavior of requesting a different remote resource when a link is clicked, the router instead sets the URL\nlocally to point to a valid route in your application. The router then detects this change and then decides what to\nrender.\n\nYew provides router support in the `yew-router` crate. To start using it, add the dependency to your `Cargo.toml`:\n\n```sh\ncargo add yew-router\n```\n\nThe utilities needed are provided under `yew_router::prelude`,\n\n## Usage\n\nYou start by defining a `Route`.\n\nRoutes are defined as an `enum` which derives `Routable`. This enum must be `Clone + PartialEq`.\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\nA `Route` is paired with a `<Switch />` component, which finds the variant whose path matches the browser's\ncurrent URL and passes it to the `render` callback. The callback then decides what to render. In case no path is\nmatched, the router navigates to the path with `not_found` attribute. If no route is specified, nothing is rendered, and\na message is logged to the console stating that no route was matched.\n\nMost of yew-router's components, in particular `<Link />` and `<Switch />`, must be (grand-)children of one of the Router components\n(e.g. `<BrowserRouter />`). You usually only need a single Router in your app, most often rendered immediately by your most top-level `<App />`\ncomponent. The Router registers a context, which is needed for Links and Switches to function. An example is shown below.\n\n:::caution\nWhen using `yew-router` in a browser environment, `<BrowserRouter />` is highly recommended.\nYou can find other router flavors in the [API Reference](https://docs.rs/yew-router/).\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### Path Segments\n\nIt is also possible to extract information from a route using dynamic and named wildcard segments.\nYou can then access the post's id inside `<Switch />` and forward it to the appropriate component via properties.\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\nYou can have a normal `Post` variant instead of `Post {id: String}` too. For example, when `Post` is rendered\nwith another router, the field can then be redundant as the other router can match and handle the path. See the\n[Nested Router](#nested-router) section below for details\n:::\n\nNote the fields must implement `Clone + PartialEq` as part of the `Route` enum. They must also implement\n`std::fmt::Display` and `std::str::FromStr` for serialization and deserialization. Primitive types like integer, float,\nand String already satisfy the requirements.\n\nIn case when the form of the path matches, but the deserialization fails (as per `FromStr`). The router will consider\nthe route as unmatched and try to render the not found route (or a blank page if the not found route is unspecified).\n\nConsider this example:\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch function renders News and id as is. Omitted here.\n```\n\nWhen the segment goes over 255, `u8::from_str()` fails with `ParseIntError`, the router will then consider the route\nunmatched.\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\nFor more information about the route syntax and how to bind parameters, check\nout [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params).\n\n### Location\n\nThe router provides a universal `Location` struct via context which can be used to access routing information.\nThey can be retrieved by hooks or convenient functions on `ctx.link()`.\n\n### Navigation\n\n`yew_router` provides a handful of tools to work with navigation.\n\n#### Link\n\nA `<Link />` renders as an `<a>` element, the `onclick` event handler will call\n[preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault), and push the targeted page to the\nhistory and render the desired page, which is what should be expected from a Single Page App. The default `onclick` of a\nnormal anchor element would reload the page.\n\nThe `<Link />` component also passes its children to the `<a>` element. Consider it a replacement of `<a/>` for in-app\nroutes. Except you supply a `to` attribute instead of a `href`. An example usage:\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\nStruct variants work as expected too:\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### Navigator API\n\nNavigator API is provided for both function components and struct components. They enable callbacks to change the\nroute. A `Navigator` instance can be obtained in either case to manipulate the route.\n\n##### Function Components\n\nFor function components, the `use_navigator` hook re-renders the component when the underlying navigator provider changes.\nHere is how to implement a button that navigates to the `Home` route when clicked.\n\n```rust ,ignore\n#[component]\npub fn MyComponent() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <button {onclick}>{\"Click to go home\"}</button>\n    }\n}\n```\n\nIf you want to replace the current location instead of pushing a new location onto the stack, use `navigator.replace()`\ninstead of `navigator.push()`.\n\nYou may notice `navigator` has to move into the callback, so it cannot be used again for other callbacks. Luckily `navigator`\nimplements `Clone`, here is for example how to have multiple buttons for different routes:\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### Struct Components\n\nFor struct components, the `Navigator` instance can be obtained through the `ctx.link().navigator()` API. The rest is\nidentical to the function component case. Here is an example of a view function that renders a single button.\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### Redirect\n\n`yew-router` also provides a `<Redirect />` component in the prelude. It can be used to achieve similar effects as the\nnavigator API. The component accepts a\n`to` attribute as the target route. When a `<Redirect/>` is rendered users will be redirected to the route specified in props.\nHere is an example:\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // made-up hook `use_user`\n    let user = match use_user() {\n        Some(user) => user,\n        // Redirects to the login page when user is `None`.\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... actual page content.\n}\n```\n\n:::tip `Redirect` vs `Navigator`, which to use\nThe Navigator API is the only way to manipulate route in callbacks.\nWhile `<Redirect />` can be used as return values in a component. You might also want to use `<Redirect />` in another\nnon-component context, for example in the switch function of a [Nested Router](#nested-router).\n:::\n\n### Listening to Changes\n\n#### Function Components\n\nYou can use `use_location` and `use_route` hooks. Your components will re-render when\nprovided values change.\n\n#### Struct Components\n\nIn order to react on route changes, you can pass a callback closure to the `add_location_listener()` method of `ctx.link()`.\n\n:::note\nThe location listener will get unregistered once it is dropped. Make sure to store the handle inside your\ncomponent state.\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // handle event\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` and `ctx.link().route::<R>()` can also be used to retrieve the location and the route once.\n\n### Query Parameters\n\n#### Specifying query parameters when navigating\n\nIn order to specify query parameters when navigating to a new route, use either `navigator.push_with_query` or\nthe `navigator.replace_with_query` functions. It uses the `ToQuery` trait to serialize the parameters into a query string for the URL. The `ToQuery` trait is automatically implemented for `serde` so any type that implements `Serialize` can be passed. In its simplest form, this is just a `HashMap` containing string pairs. In more complex scenarios the `ToQuery` trait can be implemented manually for a custom query format.\n\n#### Obtaining query parameters for the current route\n\n`location.query` is used to obtain the query parameters. It uses the `FromQuery` trait to deserialize the parameters from the query string\nin the URL. The `FromQuery` trait is automatically implemented for `serde` so any type that implements `Deserialize` can be passed. If the URL is formatted in an custom way, a manual implementation of `FromQuery` can be used.\n\n## Nested Router\n\nNested router can be useful when the app grows larger. Consider the following router structure:\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nThe nested `SettingsRouter` handles all URLs that start with `/settings`. Additionally, it redirects URLs that are not\nmatched to the main `NotFound` route. So `/settings/gibberish` will redirect to `/404`.\n\n:::caution\n\nThough note that this is still a work in progress so the way we do this is not final\n\n:::\n\nIt can be implemented with the following code:\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### Basename\n\nIt's possible to define a basename with `yew-router`.\nA basename is a common prefix of all routes. Both the Navigator API and\n`<Switch />` component respect basename setting. All pushed routes will be\nprefixed with the basename and all switches will strip the basename before\ntrying to parse the path into a `Routable`.\n\nIf a basename prop is not supplied to the Router component, it will use\nthe href attribute of the `<base />` element in your HTML file and\nfallback to `/` if no `<base />` is present in the HTML file.\n\n## Relevant examples\n\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## API Reference\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/docs/concepts/suspense.mdx",
    "content": "---\ntitle: 'Suspense'\ndescription: 'Suspense for data fetching'\n---\n\nSuspense is a way to suspend component rendering whilst waiting a task\nto complete and a fallback (placeholder) UI is shown in the meanwhile.\n\nIt can be used to fetch data from server, wait for tasks to be completed\nby an agent, or perform other background asynchronous task.\n\nBefore suspense, data fetching usually happens after (Fetch-on-render) or before\ncomponent rendering (Fetch-then-render).\n\n### Render-as-You-Fetch\n\nSuspense enables a new approach that allows components to initiate data request\nduring the rendering process. When a component initiates a data request,\nthe rendering process will become suspended and a fallback UI will be\nshown until the request is completed.\n\nThe recommended way to use suspense is with hooks.\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\nIn the above example, the `use_user` hook will suspend the component\nrendering while user information is loading and a `Loading...` placeholder will\nbe shown until `user` is loaded.\n\nTo define a hook that suspends a component rendering, it needs to return\na `SuspensionResult<T>`. When the component needs to be suspended, the\nhook should return a `Err(Suspension)` and users should unwrap it with\n`?` in which it will be converted into `Html`.\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### Note on implementing suspending hooks\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) returns 2 values: the suspension context itself, and a suspension handle.\nThe latter is the one responsible for signaling when to re-render the suspended components, it provides 2 interchangeable ways to do so:\n\n1. Calling its [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) method.\n2. Dropping the handle.\n\n:::danger\n\nThe suspension handle must be stored until it's time to update components, i.e. with newly received data;\notherwise, the suspended components will enter an infinite re-render loop, thus hampering performance.\nIn the example above, the suspension handle is preserved by being moved into a closure and passed into `on_load_user_complete`.\nWhen the hypothetical user will be loaded, the closure will be called, thus calling `handle.resume()` and re-rendering the components associated with the suspension context.\n\n:::\n\n# Complete Example\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // implementation omitted.\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // implementation omitted.\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### Use Suspense in Struct Components\n\nIt's not possible to suspend a struct component directly. However, you\ncan use a function component as a [Higher Order Component](../advanced-topics/struct-components/hoc)\nto achieve suspense-based data fetching.\n\nThe [suspense example in the Yew repository](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)\ndemonstrates how to use.\n\n## Relevant examples\n\n- [Suspense](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/docs/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'Build a sample app'\n---\n\nOnce you have the environment ready, you can either choose to use a starter template that contains\nthe boilerplate needed for a basic Yew app or manually set up a small project.\n\n## Using a starter template\n\nInstall [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) by following their installation instructions\nthen take the following steps:\n\n### Checkout and customize project\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n### Run project\n\n```shell\ntrunk serve\n```\n\n:::note\n\nTrunk [has a bug](https://github.com/trunk-rs/trunk/issues/852) on windows when `trunk serve` command fails. To workaround the issue you can run `trunk build` before running `trunk serve`.\n\n:::\n\n## Setting up the application manually\n\n### Create Project\n\nTo get started, create a new cargo project.\n\n```bash\ncargo new yew-app\n```\n\nOpen the newly created directory.\n\n```bash\ncd yew-app\n```\n\n### Run a hello world example\n\nTo verify the Rust environment is set up, run the initial project using `cargo run`. You should see\na \"Hello World!\" message.\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### Setting up the project as a Yew web application\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\n\n#### Update Cargo.toml\n\nAdd `yew` to the list of dependencies.\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n# this is the development version of Yew\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n#### Update main.rs\n\nWe need to generate a template that sets up a root Component called `App` which renders a button\nthat updates its value when clicked. Replace the contents of `src/main.rs` with the following code.\n\n:::note\nThe call to `yew::Renderer::<App>::new().render()` inside the `main` function starts your application and mounts\nit to the page's `<body>` tag.\nIf you would like to start your application with any dynamic properties, you can instead use `yew::Renderer::<App>::with_props(..).render()`.\nIf you would like to mount your application to a specific element rather than the `<body>` tag, use `yew::Renderer::<App>::with_root(element).render()` where `element` is a `web_sys::Element`.\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### Create index.html\n\nFinally, add an `index.html` file in the root directory of your app.\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## View your web application\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve\n```\n\n:::info\nAdd option '--open' to open your default browser `trunk serve --open`.\n:::\n\nTrunk will rebuild your application if you modify any of its source code files.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\n## Congratulations\n\nYou have now successfully set up your Yew development environment, and built your first web application.\n\nExperiment with this application and review the [examples](./examples.mdx) to further your learning.\n"
  },
  {
    "path": "website/docs/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'Editor setup'\ndescription: 'Setting your code editor'\n---\n\n:::important contribute\nUsing a different editor? Feel free to add instructions for your editor of choice.\n:::\n\n## Add a template for creating components\n\n### JetBrains IDEs\n\n1. Navigate to File | Settings | Editor | Live Templates.\n2. Select Rust and click on the + icon to add a new Live Template.\n3. Give it a name and description of your preference.\n4. Paste the following snippet(s) into the Template Text section.\n5. Change the applicability on the lower right, select Rust > Item > Module\n\nFor function components, use the following template.\n\n- (Optional) Click on Edit Variable and give `tag` a reasonable default value like \"div\", with double quotes.\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\nFor struct components, you can use the following more complicated template.\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. Navigate to File > Preferences > User Snippets.\n2. Select Rust as the language.\n3. Add the following snippet in the snippet JSON file:\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## Support for the `html!` macro\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### The Rust-Yew extension\n\n> 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)\n\nThe Rust-Yew extension is [available on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlighting, renames, hover, and more.\n\nEmmet support should work out of the box; if not, please fall back to editing the `settings.json` file:\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> The below configuration works with [LazyVim](https://www.lazyvim.org) and the lazy.vim plugin. Create a file in `lua/plugins/nvim-lspconfig.lua` (or update your `lspconfig`) with:\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/docs/getting-started/examples.mdx",
    "content": "---\ntitle: 'Examples'\n---\n\nThe Yew repository contains many [examples] (in various states of maintenance).\nWe recommend perusing them to get a feel for how to use different features of the framework.\nWe also welcome Pull Requests and issues for when they inevitably get neglected and need some ♥️\n\nFor more details including a list of examples, refer to the [README].\n\n:::tip\nMost of the examples have a live deployment that can be found at `https://examples.yew.rs/< example_name >`.\nClick the shield on their README page in their respective sub-folder to navigate to the live demo.\n:::\n\n[examples]: https://github.com/yewstack/yew/tree/master/examples\n[readme]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/docs/getting-started/introduction.mdx",
    "content": "---\ntitle: 'Getting Started'\n---\n\nYou will need a couple of tools to compile, build, package, and debug your Yew application.\nWhen getting started, we recommend using [Trunk](https://trunkrs.dev/). Trunk is a Wasm web application\nbundler for Rust.\n\n## Install Rust\n\nTo install Rust, follow the [official instructions](https://www.rust-lang.org/tools/install).\n\n:::important\nThe minimum supported Rust version (MSRV) for Yew is `1.84.0`. Older versions will not compile.\nYou can check your toolchain version using\n`rustup show` (under \"active toolchain\") or `rustc --version`. To update your\ntoolchain, run `rustup update`.\n:::\n\n## Install WebAssembly target\n\nRust can compile source codes for different \"targets\" (e.g. different processors). The compilation\ntarget for browser-based WebAssembly is called `wasm32-unknown-unknown`. The following command will\nadd the WebAssembly target to your development environment.\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Install Trunk\n\nTrunk is the recommended tool for managing deployment and packaging and is used throughout the\ndocumentation and examples.\n\n```shell\n# note that this might take a while to install because it compiles everything from scratch\n# Trunk also provides prebuilt binaries for a number of major package managers\n# See https://trunkrs.dev/#install for further details\ncargo install --locked trunk\n```\n\n### Other options\n\nThere are options other than Trunk that may be used for bundling Yew applications. You might want to try one of these options:\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (still in early development)\n\n## Next steps\n\nWith your development environment set up, you can now either proceed with reading the documentation, or\nif you like to learn by getting your hands dirty, we recommend you check out our [tutorial](../tutorial).\n"
  },
  {
    "path": "website/docs/migration-guides/yew/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\n## `_as_body` variant of `start_app` is removed\n\nThis method of controlling body has caused issues in event registration and\nSSR hydration. They have been removed. Read more in the [github issue](https://github.com/yewstack/yew/pull/2346).\n\n## New Hooks and Function Components API\n\nThe Function Components and Hooks API are re-implemented with a different mechanism:\n\n- User-defined hooks are now required to have a prefix `use_` and must be marked with the `#[hook]` attribute.\n- Hooks will now report compile errors if they are not called from the top level of a function component\n  or a user defined hook. The limitation existed in the previous version of Yew as well. In this version,\n  It is reported as a compile time error.\n\n## Automatic Message Batching\n\nThe scheduler now schedules its start to the end of the browser event loop.\nAll messages queued during in the meantime will be run in batch.\nThe running order of messages between components are no longer guaranteed, but\nmessages sent to the same component is still acknowledged in an FIFO order.\nIf multiple updates will result in a render, the component will be rendered\nonce.\n\n:::info What this means to developers?\n\nFor struct components, this means that if you send 2 messages to 2 different\ncomponents, they will not be guaranteed to be seen in the same order they are\nsent. If you send 2 messages to the same component, they will still be passed\nto the component in the order they are sent. The messages are not sent to the\ncomponent immediately so you should not assume that when the component receives\na message it still has the same state at the time the message is created.\n\nFor function components, if you store states with `use_state(_eq)`\nand the new value of that state depends on the previous value,\nyou may want to switch to `use_reducer(_eq)`. The new value of the state will\nnot be visible / acknowledged until the next time the component is rendered.\nThe reducer action works similar to messages for struct components and\nwill be sent to the reducer function in the same order as they are dispatched.\nThe reducer function can see all previous changes at the time they are run.\n\n:::\n\n## Yew Renderer\n\n`start_app*` has been replaced by `yew::Renderer`.\n\nYou need to enable feature `csr` to use `yew::Renderer`.\n\n## `ref` prop for Components\n\nComponents no longer have a `ref` prop. Trying to add a node ref to a component\nwill result in a compile error\n\nPreviously node ref passed to a component was bound to the first element rendered by it.\nIf this behavior is still desired, it is recommended to use add a `r#ref` field to the\ncomponent's properties and bind it manually\n\n## `changed` Method on Components\n\nThe method `fn changed()` has now a new argument to provide the old properties\nto the function.\n\nThe old method's signature was:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>) -> bool\n```\n\nThe new method's signature is now:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool\n```\n\nThis can be adjusted automatically in your code using this bash script (save\nyour code before running this!):\n\n```bash\nperl -p -i -e  's/fn changed\\(&mut self, (\\w+): &Context<Self>\\)/fn changed(&mut self, $1: &Context<Self>, _old_props: &Self::Properties)/g' $(find . -name \\*.rs)\n```\n"
  },
  {
    "path": "website/docs/migration-guides/yew/from-0_20_0-to-0_21_0.mdx",
    "content": "---\ntitle: 'From 0.20.0 to 0.21.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Dependencies as first hook argument and `use_effect_with`\n\n- Replace `use_effect_with_deps` with new `use_effect_with`\n- `use_effect_with`, `use_callback`, `use_memo` now take dependencies as their first argument\n\n### Automated refactor\n\nWith the help of [https://ast-grep.github.io](https://ast-grep.github.io/guide/quick-start.html)\nHere are commands that can do the refactoring for you.\n\n```bash\nsg --pattern 'use_effect_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_effect_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_callback($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_callback($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_callback($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_callback($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_memo($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_memo($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_future_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_future_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n```\n\n### Reasoning\n\nThis will enable more ergonomic use of hooks, consider:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\n{\n    let id = some_dep.id(); // Have to extract it in advance, some_dep is moved already in the second argument\n    use_effect_with_dep(move |_| { todo!(); drop(some_dep); }, id);\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\nuse_effect_with(some_dep.id(), move |_| { todo!(); drop(some_dep); });\n\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/docs/migration-guides/yew/from-0_21_0-to-0_22_0.mdx",
    "content": "---\ntitle: 'From 0.21.0 to 0.22.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## MSRV raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. Update your toolchain:\n\n```bash\nrustup update stable\n```\n\n## `#[function_component]` renamed to `#[component]`\n\nThe `#[function_component]` attribute has been renamed to `#[component]` for brevity. The old name is deprecated but still works.\n\n### Automated refactor\n\n```bash\n# Using sed (simple but also replaces in comments/strings)\nfind . -name \"*.rs\" -exec sed -i 's/#\\[function_component\\]/#[component]/g' {} +\nfind . -name \"*.rs\" -exec sed -i 's/#\\[function_component(/#[component(/g' {} +\n\n# Or using ast-grep (recommended - AST-aware, preserves comments/strings)\n# Important: Run the named pattern FIRST to preserve component names\nast-grep run -p '#[function_component($$$ARGS)]' -r '#[component($$$ARGS)]' -l rust --update-all .\nast-grep run -p '#[function_component]' -r '#[component]' -l rust --update-all .\n```\n\n:::note\nThe sed commands will also replace occurrences in comments and strings. Use ast-grep for more precise refactoring.\n:::\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\n#[function_component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello\"}</div> }\n}\n\n#[function_component(Named)]\nfn AnotherComponent() -> Html {\n    html! { <div>{\"World\"}</div> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\n#[component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello\"}</div> }\n}\n\n#[component(Named)]\nfn AnotherComponent() -> Html {\n    html! { <div>{\"World\"}</div> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `class=(...)` syntax removed\n\nThe deprecated `class=(expr)` syntax has been removed. Use `class={classes!(...)}` instead.\n\n### Finding occurrences\n\n```bash\n# Find all files using the old class=(...) syntax\ngrep -rn \"class=(\" --include=\"*.rs\" .\n```\n\n### Manual refactor\n\nThe transformation is straightforward: wrap the tuple contents with `classes!()` and change parentheses to braces:\n\n- `class=(a, b)` → `class={classes!(a, b)}`\n- `class=(expr)` → `class={classes!(expr)}`\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nhtml! {\n    <div class=(some_class, other_class)>{\"Content\"}</div>\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nhtml! {\n    <div class={classes!(some_class, other_class)}>{\"Content\"}</div>\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `ToHtml` trait removed\n\nThe `ToHtml` trait has been removed. Use `IntoPropValue` for custom type conversions.\n\n## For-loops in `html!` macro\n\nYou can now use for-loops directly in the `html!` macro. This is optional but provides cleaner syntax:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before (still works)\" default>\n\n```rust ,ignore\nhtml! {\n    <ul>\n        { for items.iter().map(|item| html! { <li key={item.id}>{ &item.name }</li> }) }\n    </ul>\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After (new syntax)\">\n\n```rust ,ignore\nhtml! {\n    <ul>\n        for item in items {\n            <li key={item.id}>{ &item.name }</li>\n        }\n    </ul>\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `use_effect_with` no longer requires `|| ()` return\n\nEffect hooks no longer require returning `|| ()` when there's no cleanup:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nuse_effect_with(deps, |deps| {\n    // do something\n    || ()  // had to return this\n});\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nuse_effect_with(deps, |deps| {\n    // do something\n    // no return needed!\n});\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/docs/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: 'From 0.22.0 to 0.23.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` no longer re-renders on identity dispatches\n\n`use_reducer` now skips re-rendering when the reducer returns the same `Rc` (checked by pointer equality). Previously, every dispatch triggered a re-render regardless.\n\nIf your reducer has a code path that returns `self` unchanged and you relied on that causing a re-render, replace it with `use_force_update`:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // This no longer triggers a re-render in 0.23!\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"Refresh\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"Refresh\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/docs/migration-guides/yew-agent/from-0_0_0-to-0_1_0.mdx",
    "content": "---\ntitle: 'From 0.0.0 to 0.1.0'\n---\n\nThis is the first release of `yew-agents` being separated from `yew`\n\nThe only thing you will need to do is change the import paths from `yew::*` to `yew_agents::*`\n"
  },
  {
    "path": "website/docs/migration-guides/yew-agent/from-0_1_0-to-0_2_0.mdx",
    "content": "---\ntitle: 'From 0.1.0 to 0.2.0'\n---\n\n## Removal of `Context` and `Job` Agents\n\nThe `Context` and `Job` Agents have been removed in favour of Yew's Context API.\n\nYou can see the updated [`pub_sub`](https://github.com/yewstack/yew/tree/master/examples/pub_sub)\nwhich demonstrate how to use the context API.\n\nFor users of `yew_agent::utils::store`, you may switch to third party solutions like: [Yewdux](https://github.com/intendednull/yewdux) or [Bounce](https://github.com/futursolo/bounce).\n\n## `Threaded` has been separated into `PublicAgent` and `PrivateAgent`\n\nReplace `use yew_agent::Threaded;` with `use yew_agent::PublicAgent;`.\n\n:::note\n\n`Threaded` was never implemented for Private Agents.\nAll existing web worker-based agents are Public Agents.\n\n:::\n"
  },
  {
    "path": "website/docs/migration-guides/yew-agent/from-0_3_0-to-0_4_0.mdx",
    "content": "---\ntitle: 'From 0.3.0 to 0.4.0'\n---\n\n## MSRV raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. Update your toolchain:\n\n```bash\nrustup update stable\n```\n\n## gloo-worker vendored\n\nThe external dependency on `gloo-worker` has been removed. All worker functionality is now built into `yew-agent`.\n\n### Update imports\n\nIf you were importing types from `gloo-worker`, update to import from `yew_agent`:\n\n```rust ,ignore\n// Before\nuse gloo_worker::{Spawnable, Worker, WorkerScope};\n\n// After\nuse yew_agent::prelude::*;\n// or\nuse yew_agent::{Spawnable, Worker, WorkerScope};\n```\n\n### Codec trait\n\nThe `Codec` trait is now defined in `yew-agent`:\n\n```rust ,ignore\n// Before\nuse gloo_worker::Codec;\n\n// After\nuse yew_agent::Codec;\n```\n"
  },
  {
    "path": "website/docs/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: 'From 0.4.0 to 0.5.0'\n---\n\nNo breaking changes. Update yew-agent to 0.5.0 in your `Cargo.toml`.\n"
  },
  {
    "path": "website/docs/migration-guides/yew-router/from-0_15_0-to-0_16_0.mdx",
    "content": "---\ntitle: 'From 0.15.0 to 0.16.0'\n---\n\nThe router API has been completely rewritten in `0.16.0`.\n\nBecause it is such a radical change, there are too many things to list out here, so we highly\nrecommend to read the updated [router documentation](./../../concepts/router) and adapt your app\naccordingly.\n"
  },
  {
    "path": "website/docs/migration-guides/yew-router/from-0_16_0-to-0_17_0.mdx",
    "content": "---\ntitle: 'From 0.16.0 to 0.17.0'\n---\n\n## `Switch::render` is no longer needed\n\nThe `<Switch />` component now accepts a closure of `Fn(Routable) -> Html` as\nthe render function directly.\n\n## `navigator` API\n\nThe History API has been replaced with the Navigator API.\n"
  },
  {
    "path": "website/docs/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\nNo breaking changes. Update yew-router to 0.20.0 in your `Cargo.toml`.\n"
  },
  {
    "path": "website/docs/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nYew does not ship built-in CSS support, but the community maintains several styling\nsolutions. Below are actively maintained projects you can use today.\n\n#### Styling Solutions\n\n- [stylist](https://github.com/futursolo/stylist-rs) - A CSS-in-Rust styling solution.\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind Utility Classes.\n\n:::important contribute\nIf you're developing a project adding styles to Yew please submit a PR adding yourself to this list!\n:::\n\n---\n\n#### Inactive Projects\n\nThe projects below are no longer actively maintained but may still serve as useful\nreferences for learning or as starting points for new efforts. If you're interested\nin reviving or continuing any of them, contributions are welcome!\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - A styling framework for Yew without any JavaScript dependencies.\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design Components.\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS Components.\n- [Yewtify](https://github.com/yewstack/yewtify) – Implements the features provided by the Vuetify framework in Yew.\n"
  },
  {
    "path": "website/docs/more/debugging.mdx",
    "content": "---\ntitle: 'Debugging'\n---\n\n## Panics\n\nYew automatically logs panics in the browser console.\n\n## Console Logging\n\nIn JavaScript, `console.log()` is used to log to the browser console. Some options for Yew are listed below.\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate integrates with [`log`](https://crates.io/crates/log) crate to send the log level, source line, and filename to the browser console.\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nThis crate is part of Gloo, a collection of libraries providing ergonomic Rust wrappers for browser APIs.\nThe `log!` macro can take a `JsValue` directly which is slightly easier to use than `wasm_logger`.\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` can be used with [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) to output messages to the browser console.\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## Debugging component lifecycles\n\n[`tracing`](https://crates.io/crates/tracing) can be used to collect event information related to a component's lifecycle. `tracing` also comes with a feature flag for `log` support, which integrates nicely with `wasm-logger`.\n\n[Compile time filters](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) can be used to adjust verbosity or disable logging, which should result in a smaller Wasm file.\n\n## Source Maps\n\nThere is [some support](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) for source maps.\nHowever, some configuration is required.\n\n## Past Articles\n\nSome past articles on the state of debugging in WebAssembly in Rust can be found below. They may serve as interesting reads.\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) does not support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/docs/more/deployment.mdx",
    "content": "---\ntitle: 'Deployment'\ndescription: 'Deploying Yew applications'\n---\n\nWhen you are ready to deploy your Yew application to a server, you have various options for deployment.\n\n`trunk build --release` builds your app in release mode. Set up your HTTP server so that it serves `index.html` whenever your site is visited, and requests to static paths like `index_<hash>.js` and `index_bg_<hash>.wasm` are served with the contents of their respective contents from the dist directory generated by trunk.\n\n:::important A note about `trunk serve --release`\nDo **not** use `trunk serve --release` to serve your application in production.\nIt should only be used for testing the release build during development\n:::\n\n## Server configuration\n\n### Serving `index.html` as a fallback\n\nIf the application uses the [Yew router](concepts/router.mdx), you must configure the server to return the `index.html` when asked for a file that it does not have.\n\nAn application with Yew router is built as a [Single Page Application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA). When the user navigates to a URL from within a running client, the router interprets the URL and routes to that page.\n\nBut on a fresh load, such as when navigating to the page by entering it in the address bar or refreshing the page, all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router. A wrongly configured server would return with the status 404 - Not Found.\n\nBy returning `index.html` instead, the app loads as it normally would, as if the request was for `/` until the router notices that the route is `/show/42` and displays the appropriate contents.\n\n### Configuring correct MIME-type for Web Assembly asset.\n\nThe WASM files must be served with the [Content-Type header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) set to `application/wasm` MIME-type.\n\nMost servers and hosting services already do this by default. If yours does not, consult its documentation. An incorrect MIME type will, in most web browsers, result in an error similar to the following:\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## Building for Relative Paths\n\nBy default, trunk will assume that your site is being served at `/` and build the site accordingly. This behavior can be overridden by adding `<base data-trunk-public-url />` to the `index.html` file. Trunk rewrites this tag to contain the value passed to `--public-url`. Yew router automatically detects the presence of `<base />` and handles it appropriately.\n\n## Customizing behavior using environment variables\n\nIt is common to customize the build environment by using environment variables. Since the app is run in a browser, we cannot read the environment variables at runtime.\nThe [`std::env!`](https://doc.rust-lang.org/std/macro.env.html) macro can be used to obtain a value of an environment variable at compile time.\n"
  },
  {
    "path": "website/docs/more/roadmap.mdx",
    "content": "---\ntitle: 'Roadmap'\ndescription: 'The planned feature roadmap for the Yew framework'\n---\n\n## Prioritization\n\nThe prioritization of upcoming features and focuses of the framework is determined by the community.\nIn Spring 2020, a developer survey was sent out to collect feedback on the direction of the project.\nYou can find the summary in the [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D).\n\n:::note\nStatus of all major initiatives can be tracked on the Yew Github [project board](https://github.com/yewstack/yew/projects)\n:::\n\n## Focuses\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Most requested features\n\n1. [Functional Components](https://github.com/yewstack/yew/projects/3)\n2. [Component Library](https://github.com/yewstack/yew/projects/4)\n3. Better state management\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n### Issues needed for production readiness\n\n- Improve Yew test coverage\n- Reduce binary size\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- Create tutorial\n- Simplify project setup\n\n### Pain points\n\n- [Component boilerplate](https://github.com/yewstack/yew/issues/830)\n- [Agents](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/docs/more/testing.mdx",
    "content": "---\ntitle: 'Testing apps'\ndescription: 'Testing your app'\n---\n\n:::info\nWe are working on making it easy to test components, but this is currently a work in progress.\n\nSupport for [shallow rendering](https://github.com/yewstack/yew/issues/1413) can be found in the GitHub repository.\n:::\n\n## Snapshot testing\n\nYew exposes the `yew::tests::layout_tests` module to facilitate snapshot testing of components.\n\n:::important contribute\nHelp improve the documentation for snapshot testing.\n:::\n\n## wasm_bindgen_test\n\nThe Rust/WASM working group maintains a crate called [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nwhich allows you to run tests in a browser in a similar fashion to how the built-in `#[test]` procedural macro works.\nMore information is given in the [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nfor this module.\n"
  },
  {
    "path": "website/docs/tutorial/index.mdx",
    "content": "---\ntitle: 'Tutorial'\nslug: /tutorial\n---\n\n## Introduction\n\nIn this hands-on tutorial, we will take a look at how we can use Yew to build web applications.\n**Yew** is a modern [Rust](https://www.rust-lang.org/) framework for building front-end web apps using [WebAssembly](https://webassembly.org/).\nYew encourages a reusable, maintainable, and well-structured architecture by leveraging Rust's powerful type system.\nA large ecosystem of community-created libraries, known in Rust as [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html),\nprovide components for commonly-used patterns such as state management.\n[Cargo](https://doc.rust-lang.org/cargo/), the package manager for Rust, allows us to take advantage of the\nnumerous crates available on [crates.io](https://crates.io), such as Yew.\n\n### What we are going to build\n\nRustconf is an intergalactic gathering of the Rust community that happens annually.\nRustconf 2020 had a plethora of talks that provided a good amount of information.\nIn this hands-on tutorial, we will be building a web application to help fellow Rustaceans\nget an overview of the talks and watch them all from one page.\n\n## Setting up\n\n### Prerequisites\n\nThis tutorial assumes you are already familiar with Rust. If you are new to Rust,\nthe free [Rust Book](https://doc.rust-lang.org/book/ch00-00-introduction.html) offers a great starting point for\nbeginners and continues to be an excellent resource even for experienced Rust developers.\n\nEnsure the latest version of Rust is installed by running `rustup update` or by\n[installing rust](https://www.rust-lang.org/tools/install) if you have not already done so.\n\nAfter installing Rust, you can use Cargo to install `trunk` by running:\n\n```bash\ncargo install trunk\n```\n\nWe will also need to add the WASM build target by running:\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### Setting up the project\n\nFirst, create a new cargo project:\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nTo verify the Rust environment is set up properly, run the initial project using the cargo build tool.\nAfter the output about the build process, you should see the expected \"Hello, world!\" message.\n\n```bash\ncargo run\n```\n\n## Our first static page\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\nUpdate the files as follows:\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nNow, let's create an `index.html` at the root of the project.\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### Start the development server\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve --open\n```\n\n:::info\nRemove option '--open' to not open your default browser `trunk serve`.\n:::\n\nTrunk will open your application in your default browser, watch the project directory and helpfully rebuild your\napplication if you modify any source files.\nThis will fail if the socket is being used by another application.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\nIf you are curious, you can run `trunk help` and `trunk help <subcommand>` for more details on what is happening.\n\n### Congratulations\n\nYou have now successfully set up your Yew development environment and built your first Yew web application.\n\n## Building HTML\n\nYew makes use of Rust's procedural macros and provides us with a syntax similar to JSX (an extension to JavaScript\nwhich allows you to write HTML-like code inside JavaScript) to create the markup.\n\n### Converting classic HTML\n\nSince we already have a pretty good idea of what our website will look like, we can simply translate our mental draft\ninto a representation compatible with `html!`. If you are comfortable writing simple HTML, you should have no problem\nwriting marking inside `html!`. It is important to note that the macro does differ from HTML in a few ways:\n\n1. Expressions must be wrapped in curly braces (`{ }`)\n2. There must only be one root node. If you want to have multiple elements without wrapping them in a container,\n   an empty tag/fragment (`<> ... </>`) is used\n3. Elements must be closed properly.\n\nWe want to build a layout that looks something like this in raw HTML:\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nNow, let's convert this HTML into `html!`. Type (or copy/paste) the following snippet into the body of `app` function\nsuch that the value of `html!` is returned by the function\n\n```rust {3-21}\n#[component]\nfn App() -> Html {\n-   html! {\n-       <h1>{ \"Hello World\" }</h1>\n-   }\n+   html! {\n+       <>\n+           <h1>{ \"RustConf Explorer\" }</h1>\n+           <div>\n+               <h3>{ \"Videos to watch\" }</h3>\n+               <p>{ \"John Doe: Building and breaking things\" }</p>\n+               <p>{ \"Jane Smith: The development process\" }</p>\n+               <p>{ \"Matt Miller: The Web 7.0\" }</p>\n+               <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           </div>\n+           <div>\n+               <h3>{ \"John Doe: Building and breaking things\" }</h3>\n+               <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n+           </div>\n+       </>\n+   }\n}\n```\n\nRefresh the browser page, and you should see the following output displayed:\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### Using Rust language constructs in the markup\n\nA big advantage of writing markup in Rust is that we get all the coolness of Rust in our markup.\nNow, instead of hardcoding the list of videos in the HTML, let's define them as a `Vec` of `Video` structs.\nWe create a simple `struct` (in `main.rs` or any file of our choice) that will hold our data.\n\n```rust\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: AttrValue,\n    speaker: AttrValue,\n    url: AttrValue,\n}\n```\n\nNext, we will create instances of this struct in our `app` function and use those instead of hardcoding the data:\n\n```rust {3-29}\n#[component]\nfn App() -> Html {\n+   let videos = vec![\n+       Video {\n+           id: 1,\n+           title: \"Building and breaking things\".into(),\n+           speaker: \"John Doe\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 2,\n+           title: \"The development process\".into(),\n+           speaker: \"Jane Smith\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 3,\n+           title: \"The Web 7.0\".into(),\n+           speaker: \"Matt Miller\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 4,\n+           title: \"Mouseless development\".into(),\n+           speaker: \"Tom Jerry\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+   ];\n+\n```\n\nTo display them, we can use a `for` loop right in the macro in place of the hardcoded HTML:\n\n```rust {6-12}\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <p>{ \"John Doe: Building and breaking things\" }</p>\n-               <p>{ \"Jane Smith: The development process\" }</p>\n-               <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-               <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+               for video in &videos {\n+                   <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+               }\n            </div>\n            // ...\n        </>\n    }\n```\n\n:::tip\nKeys on list items help Yew keep track of which items have changed in the list, resulting in faster re-renders.\n[It is always recommended to use keys in lists](/concepts/html/lists.mdx#keyed-lists).\n:::\n\n## Components\n\nComponents are the building blocks of Yew applications. By combining components, which can be made of other components,\nwe build our application. By structuring our components for re-usability and keeping them generic, we will be able to use\nthem in multiple parts of our application without having to duplicate code or logic.\n\nThe `app` function we have been using so far is a component, called `App`. It is a \"function component\".\nThere are two different types of components in Yew.\n\n1. Struct Components\n2. Function Components\n\nIn this tutorial, we will be using function components.\n\nNow, let's split up our `App` component into smaller components. We begin by extracting the videos list into\nits own component.\n\n```rust\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component]\nfn VideosList(VideosListProps { videos }: &VideosListProps) -> Html {\n    html! {\n        for video in videos {\n            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }\n}\n```\n\nNotice the parameters of our `VideosList` function component. A function component takes only one argument which\ndefines its \"props\" (short for \"properties\"). Props are used to pass data down from a parent component to a child component.\nIn this case, `VideosListProps` is a struct that defines the props.\n\n:::important\nThe struct used for props must implement `Properties` by deriving it.\n:::\n\nNow, we can update our `App` component to make use of `VideosList` component.\n\n```rust {9-12}\n#[component]\nfn App() -> Html {\n    // ...\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               for video in &videos {\n-                   <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-               }\n+               <VideosList {videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nBy looking at the browser window, we can verify that the lists are rendered as they should be.\nWe have moved the rendering logic of lists to its component. This shortens the `App` component’s source code,\nmaking it easier for us to read and understand.\n\n### Making it interactive\n\nThe final goal here is to display the selected video. To do that, `VideosList` component needs to \"notify\" its\nparent when a video is selected, which is done via a `Callback`. This concept is called \"passing handlers\".\nWe modify its props to take an `on_click` callback:\n\n```rust {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+   on_click: Callback<Video>,\n}\n```\n\nThen we modify the `VideosList` component to \"emit\" the selected video to the callback.\n\n```rust {2-18}\n#[component]\n-fn VideosList(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn VideosList(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+   let on_select = |video: &Video| {\n+       let on_click = on_click.clone();\n+       let video = video.clone();\n+       Callback::from(move |_| {\n+           on_click.emit(video.clone())\n+       })\n+   };\n+\n    html! {\n        for video in videos {\n-           <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+           <p key={video.id} onclick={on_select(video)}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }\n}\n```\n\nNext, we need to modify the usage of `VideosList` to pass that callback. But before doing that, we should create\na new component, `VideoDetails`, that is displayed when a video is clicked.\n\n```rust\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component]\nfn VideoDetails(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ &*video.title }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\nNow, modify the `App` component to display `VideoDetails` component whenever a video is selected.\n\n```rust {3-11,18-19,21-28}\n        },\n    ];\n+\n+   let selected_video = use_state(|| None);\n+\n+   let on_video_select = {\n+       let selected_video = selected_video.clone();\n+       Callback::from(move |video: Video| {\n+           selected_video.set(Some(video))\n+       })\n+   };\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <VideosList {videos} />\n+               <VideosList {videos} on_click={on_video_select} />\n            </div>\n+           if let Some(video) = &*selected_video {\n+               <VideoDetails video={video.clone()} />\n+           }\n-           <div>\n-               <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-               <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-           </div>\n        </>\n    }\n}\n```\n\n### Handling state\n\nRemember the `use_state` used earlier? That is a special function, called a \"hook\". Hooks are used to \"hook\" into\nthe lifecycle of a function component and perform actions. You can learn more about this hook, and others\n[here](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks).\n\n:::note\nStruct components act differently. See [the documentation](advanced-topics/struct-components/introduction.mdx) to learn about those.\n:::\n\n## Fetching data (using external REST API)\n\nIn a real-world application, data will usually come from an API instead of being hardcoded. Let's fetch our\nvideos list from an external source. For this we will need to add the following crates:\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  For making the fetch call.\n- [`serde`](https://serde.rs) with derive features\n  For de-serializing the JSON response\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  For executing Rust Future as a Promise\n\nLet's update the dependencies in `Cargo.toml` file:\n\n```toml title=\"Cargo.toml\" {2-6}\n[dependencies]\n-yew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n+yew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\", \"serde\"] }\n+gloo-net = \"0.6\"\n+serde = { version = \"1.0\", features = [\"derive\"] }\n+wasm-bindgen-futures = \"0.4\"\n```\n\nYew's `serde` feature enables integration with the `serde` crate, the important point for us is that\nit adds a `serde::Deserialize` impl to `AttrValue`.\n\n:::note\nWhen choosing dependencies make sure they are `wasm32` compatible!\nOtherwise you won't be able to run your application.\n:::\n\nUpdate the `Video` struct to derive the `Deserialize` trait:\n\n```rust {2,4-5}\nuse yew::prelude::*;\n+use serde::Deserialize;\n// ...\n-#[derive(Clone, PartialEq)]\n+#[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: AttrValue,\n    speaker: AttrValue,\n    url: AttrValue,\n}\n```\n\nNow as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data\n\n```rust {2,6-50,59-60}\nuse yew::prelude::*;\n+use gloo_net::http::Request;\n\n#[component]\nfn App() -> Html {\n-   let videos = vec![\n-       Video {\n-           id: 1,\n-           title: \"Building and breaking things\".into(),\n-           speaker: \"John Doe\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 2,\n-           title: \"The development process\".into(),\n-           speaker: \"Jane Smith\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 3,\n-           title: \"The Web 7.0\".into(),\n-           speaker: \"Matt Miller\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 4,\n-           title: \"Mouseless development\".into(),\n-           speaker: \"Tom Jerry\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-   ];\n-\n+   let videos = use_state(|| vec![]);\n+   {\n+       let videos = videos.clone();\n+       use_effect_with((), move |_| {\n+           let videos = videos.clone();\n+           wasm_bindgen_futures::spawn_local(async move {\n+               let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                   .send()\n+                   .await\n+                   .unwrap()\n+                   .json()\n+                   .await\n+                   .unwrap();\n+               videos.set(fetched_videos);\n+           });\n+           || ()\n+       });\n+   }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <VideosList {videos} on_click={on_video_select} />\n+               <VideosList videos={(*videos).clone()} on_click={on_video_select} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n:::note\nWe are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have\n[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).\n:::\n\nNow, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.\nTo fix that, we need a proxy server. Luckily trunk provides that.\n\nUpdate the following line:\n\n```rust {2-3}\n-               let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+               let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n```\n\nNow, rerun the server with the following command:\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nRefresh the tab and everything should work as expected.\n\n## Wrapping up\n\nCongratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.\n\n## What's next\n\nThis application is very far from perfect or useful. After going through this tutorial,\nyou can use it as a jumping-off point to explore more advanced topics.\n\n### Styles\n\nOur apps look very ugly. There is no CSS or any kind of style.\nUnfortunately, Yew does not offer a built-in way to style components. See [Trunk's assets](https://trunkrs.dev/assets/)\nto learn how to add style sheets.\n\n### More libraries\n\nOur app made use of only a few external dependencies. There are lots of crates out there that can be used.\nSee [external libraries](/community/external-libs) for more details.\n\n### Learning more about Yew\n\nRead our [official documentation](../getting-started/introduction.mdx). It explains a lot of concepts in much more detail.\nTo learn more about the Yew API, see our [API docs](https://docs.rs/yew).\n\n<!-- COMBINE CODE BLOCKS -->\n"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "const { API_BUTTON } = require('./src/constants')\n\nconst editUrl = 'https://github.com/yewstack/yew/blob/master/website/'\n\n/** @type {import('@docusaurus/types').DocusaurusConfig} */\nmodule.exports = {\n    title: 'Yew',\n    tagline:\n        'A framework for creating reliable and efficient web applications.',\n    url: 'https://yew.rs',\n    baseUrl: '/',\n    onBrokenLinks: 'throw',\n    favicon: 'img/logo.svg',\n    organizationName: 'yewstack', // Usually your GitHub org/user name.\n    projectName: 'yew', // Usually your repo name.\n    themeConfig: {\n        colorMode: {\n            respectPrefersColorScheme: true,\n        },\n        docs: {\n            sidebar: {\n                hideable: true,\n            },\n        },\n        navbar: {\n            title: 'Yew',\n            logo: {\n                alt: 'Yew Logo',\n                src: 'img/logo.svg',\n            },\n            items: [\n                {\n                    type: 'docsVersionDropdown',\n                    position: 'left',\n                },\n                {\n                    type: 'localeDropdown',\n                    position: 'left',\n                },\n                {\n                    type: 'doc',\n                    position: 'left',\n                    docId: 'getting-started/introduction',\n                    label: 'Docs',\n                },\n                {\n                    type: 'doc',\n                    position: 'left',\n                    docId: 'tutorial/index',\n                    label: 'Tutorial',\n                },\n                {\n                    docsPluginId: 'community',\n                    type: 'doc',\n                    position: 'right',\n                    docId: 'awesome',\n                    label: 'Community',\n                },\n                {\n                    position: 'right',\n                    to: 'blog',\n                    label: 'Blog',\n                },\n                {\n                    href: 'https://play.yew.rs/',\n                    position: 'right',\n                    label: 'Playground',\n                },\n                {\n                    href: 'https://docs.rs/yew',\n                    position: 'right',\n                    label: API_BUTTON,\n                },\n                {\n                    href: 'https://github.com/yewstack/yew',\n                    label: 'GitHub',\n                    position: 'right',\n                },\n            ],\n        },\n        footer: {\n            style: 'dark',\n            links: [\n                {\n                    title: 'Support',\n                    items: [\n                        {\n                            label: 'Sponsor Project',\n                            href: 'https://opencollective.com/yew',\n                        },\n                    ],\n                },\n                {\n                    title: 'Participate',\n                    items: [\n                        {\n                            label: 'GitHub',\n                            href: 'https://github.com/yewstack/yew',\n                        },\n                        {\n                            label: 'Discord',\n                            href: 'https://discord.gg/VQck8X4',\n                        },\n                        {\n                            label: 'Twitter',\n                            href: 'https://twitter.com/yewstack',\n                        },\n                    ],\n                },\n                {\n                    title: 'More',\n                    items: [\n                        {\n                            label: 'Yew Awesome',\n                            href: 'https://github.com/jetli/awesome-yew',\n                        },\n                    ],\n                },\n            ],\n        },\n        prism: {\n            additionalLanguages: ['rust', 'toml'],\n        },\n        algolia: {\n            appId: 'F8S2ICRD2T',\n            apiKey: '2a1c25e8b0a9c95d6d71658887ad4466',\n            indexName: 'yew-rs',\n            contextualSearch: true,\n            insights: true, // Optional, automatically send insights when user interacts with search results\n            searchPagePath: 'search',\n        },\n    },\n    i18n: {\n        defaultLocale: 'en',\n        locales: ['en', 'ja', 'zh-Hans', 'zh-Hant'],\n    },\n    markdown: {\n        hooks: {\n            onBrokenMarkdownLinks: 'warn',\n            onBrokenMarkdownImages: 'throw',\n        },\n    },\n    presets: [\n        [\n            '@docusaurus/preset-classic',\n            {\n                theme: {\n                    customCss: ['./src/css/custom.css'],\n                },\n                docs: {\n                    path: 'docs',\n                    sidebarPath: require.resolve('./sidebars/docs.js'),\n                    editUrl,\n                    routeBasePath: '/docs',\n                },\n                blog: {\n                    path: 'blog',\n                    blogTitle: 'Yew Blog',\n                    editUrl,\n                },\n                pages: {},\n                gtag: {\n                    trackingID: 'G-DENCL8P4YP',\n                    anonymizeIP: true,\n                },\n            },\n        ],\n    ],\n    plugins: [\n        'docusaurus-plugin-sass',\n        [\n            '@docusaurus/plugin-content-docs',\n            {\n                id: 'community',\n                path: 'community',\n                sidebarPath: require.resolve('./sidebars/community.js'),\n                routeBasePath: '/community',\n                editUrl,\n            },\n        ],\n        [\n            'client-redirects',\n            {\n                redirects: [\n                    // this handles the redirect from `/next` -> to the (current) first item in the docs sidebar\n                    // note: if the first item is changed, it should be reflected here\n                    {\n                        to: '/docs/next/getting-started/introduction', // string\n                        from: ['/docs/next'], // string | string[]\n                    },\n                ],\n            },\n        ],\n    ],\n}\n"
  },
  {
    "path": "website/i18n/ja/code.json",
    "content": "{\n  \"theme.ErrorPageContent.title\": {\n    \"message\": \"ページがクラッシュしました。\",\n    \"description\": \"The title of the fallback page when the page crashed\"\n  },\n  \"theme.ErrorPageContent.tryAgain\": {\n    \"message\": \"Try again\",\n    \"description\": \"The label of the button to try again rendering when the React error boundary captures an error\"\n  },\n  \"theme.NotFound.title\": {\n    \"message\": \"ページが見つかりません\",\n    \"description\": \"The title of the 404 page\"\n  },\n  \"theme.NotFound.p1\": {\n    \"message\": \"お探しのページが見つかりませんでした。\",\n    \"description\": \"The first paragraph of the 404 page\"\n  },\n  \"theme.NotFound.p2\": {\n    \"message\": \"このページにリンクしているサイトの所有者に連絡をしてリンクが壊れていることを伝えてください。\",\n    \"description\": \"The 2nd paragraph of the 404 page\"\n  },\n  \"theme.AnnouncementBar.closeButtonAriaLabel\": {\n    \"message\": \"閉じる\",\n    \"description\": \"The ARIA label for close button of announcement bar\"\n  },\n  \"theme.BackToTopButton.buttonAriaLabel\": {\n    \"message\": \"ページの先頭に戻る\",\n    \"description\": \"The ARIA label for the back to top button\"\n  },\n  \"theme.blog.archive.title\": {\n    \"message\": \"Archive\",\n    \"description\": \"The page & hero title of the blog archive page\"\n  },\n  \"theme.blog.archive.description\": {\n    \"message\": \"Archive\",\n    \"description\": \"The page & hero description of the blog archive page\"\n  },\n  \"theme.blog.paginator.navAriaLabel\": {\n    \"message\": \"ブログ記事一覧のナビゲーション\",\n    \"description\": \"The ARIA label for the blog pagination\"\n  },\n  \"theme.blog.paginator.newerEntries\": {\n    \"message\": \"新しい記事\",\n    \"description\": \"The label used to navigate to the newer blog posts page (previous page)\"\n  },\n  \"theme.blog.paginator.olderEntries\": {\n    \"message\": \"過去の記事\",\n    \"description\": \"The label used to navigate to the older blog posts page (next page)\"\n  },\n  \"theme.blog.post.readingTime.plurals\": {\n    \"message\": \"約{readingTime}分\",\n    \"description\": \"Pluralized label for \\\"{readingTime} min read\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.blog.post.readMore\": {\n    \"message\": \"もっと見る\",\n    \"description\": \"The label used in blog post item excerpts to link to full blog posts\"\n  },\n  \"theme.blog.post.paginator.navAriaLabel\": {\n    \"message\": \"ブログ記事のナビゲーション\",\n    \"description\": \"The ARIA label for the blog posts pagination\"\n  },\n  \"theme.blog.post.paginator.newerPost\": {\n    \"message\": \"新しい記事\",\n    \"description\": \"The blog post button label to navigate to the newer/previous post\"\n  },\n  \"theme.blog.post.paginator.olderPost\": {\n    \"message\": \"過去の記事\",\n    \"description\": \"The blog post button label to navigate to the older/next post\"\n  },\n  \"theme.blog.sidebar.navAriaLabel\": {\n    \"message\": \"Blog recent posts navigation\",\n    \"description\": \"The ARIA label for recent posts in the blog sidebar\"\n  },\n  \"theme.blog.post.plurals\": {\n    \"message\": \"{count}件\",\n    \"description\": \"Pluralized label for \\\"{count} posts\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.blog.tagTitle\": {\n    \"message\": \"「{tagName}」タグの記事が{nPosts}あります\",\n    \"description\": \"The title of the page for a blog tag\"\n  },\n  \"theme.tags.tagsPageLink\": {\n    \"message\": \"全てのタグを見る\",\n    \"description\": \"The label of the link targeting the tag list page\"\n  },\n  \"theme.CodeBlock.copyButtonAriaLabel\": {\n    \"message\": \"クリップボードにコードをコピー\",\n    \"description\": \"The ARIA label for copy code blocks button\"\n  },\n  \"theme.CodeBlock.copied\": {\n    \"message\": \"コピーしました\",\n    \"description\": \"The copied button label on code blocks\"\n  },\n  \"theme.CodeBlock.copy\": {\n    \"message\": \"コピー\",\n    \"description\": \"The copy button label on code blocks\"\n  },\n  \"theme.docs.sidebar.expandButtonTitle\": {\n    \"message\": \"サイドバーを開く\",\n    \"description\": \"The ARIA label and title attribute for expand button of doc sidebar\"\n  },\n  \"theme.docs.sidebar.expandButtonAriaLabel\": {\n    \"message\": \"サイドバーを開く\",\n    \"description\": \"The ARIA label and title attribute for expand button of doc sidebar\"\n  },\n  \"theme.docs.paginator.navAriaLabel\": {\n    \"message\": \"ドキュメントのナビゲーション\",\n    \"description\": \"The ARIA label for the docs pagination\"\n  },\n  \"theme.docs.paginator.next\": {\n    \"message\": \"次へ\",\n    \"description\": \"The label used to navigate to the next doc\"\n  },\n  \"theme.docs.paginator.previous\": {\n    \"message\": \"前へ\",\n    \"description\": \"The label used to navigate to the previous doc\"\n  },\n  \"theme.docs.sidebar.collapseButtonTitle\": {\n    \"message\": \"サイドバーを隠す\",\n    \"description\": \"The title attribute for collapse button of doc sidebar\"\n  },\n  \"theme.docs.sidebar.collapseButtonAriaLabel\": {\n    \"message\": \"サイドバーを隠す\",\n    \"description\": \"The title attribute for collapse button of doc sidebar\"\n  },\n  \"theme.docs.tagDocListPageTitle.nDocsTagged\": {\n    \"message\": \"One doc tagged|{count} docs tagged\",\n    \"description\": \"Pluralized label for \\\"{count} docs tagged\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.docs.tagDocListPageTitle\": {\n    \"message\": \"{nDocsTagged} with \\\"{tagName}\\\"\",\n    \"description\": \"The title of the page for a docs tag\"\n  },\n  \"theme.docs.versions.unreleasedVersionLabel\": {\n    \"message\": \"これはリリース前の{siteTitle} {versionLabel}のドキュメントです。\",\n    \"description\": \"The label used to tell the user that he's browsing an unreleased doc version\"\n  },\n  \"theme.docs.versions.unmaintainedVersionLabel\": {\n    \"message\": \"これは{siteTitle} {versionLabel}のドキュメントで現在はアクティブにメンテナンスされていません。\",\n    \"description\": \"The label used to tell the user that he's browsing an unmaintained doc version\"\n  },\n  \"theme.docs.versions.latestVersionSuggestionLabel\": {\n    \"message\": \"最新のドキュメントは{latestVersionLink} ({versionLabel}) を見てください。\",\n    \"description\": \"The label used to tell the user to check the latest version\"\n  },\n  \"theme.docs.versions.latestVersionLinkLabel\": {\n    \"message\": \"最新バージョン\",\n    \"description\": \"The label used for the latest version suggestion link label\"\n  },\n  \"theme.common.editThisPage\": {\n    \"message\": \"このページを編集\",\n    \"description\": \"The link label to edit the current page\"\n  },\n  \"theme.common.headingLinkTitle\": {\n    \"message\": \"見出しへの直接リンク\",\n    \"description\": \"Title for link to heading\"\n  },\n  \"theme.lastUpdated.atDate\": {\n    \"message\": \"{date}に\",\n    \"description\": \"The words used to describe on which date a page has been last updated\"\n  },\n  \"theme.lastUpdated.byUser\": {\n    \"message\": \"{user}が\",\n    \"description\": \"The words used to describe by who the page has been last updated\"\n  },\n  \"theme.lastUpdated.lastUpdatedAtBy\": {\n    \"message\": \"{atDate}{byUser}最終更新\",\n    \"description\": \"The sentence used to display when a page has been last updated, and by who\"\n  },\n  \"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel\": {\n    \"message\": \"← Back to main menu\",\n    \"description\": \"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)\"\n  },\n  \"theme.navbar.mobileVersionsDropdown.label\": {\n    \"message\": \"Versions\",\n    \"description\": \"The label for the navbar versions dropdown on mobile view\"\n  },\n  \"theme.common.skipToMainContent\": {\n    \"message\": \"メインコンテンツまでスキップ\",\n    \"description\": \"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation\"\n  },\n  \"theme.tags.tagsListLabel\": {\n    \"message\": \"タグ:\",\n    \"description\": \"The label alongside a tag list\"\n  },\n  \"theme.TOCCollapsible.toggleButtonLabel\": {\n    \"message\": \"On this page\",\n    \"description\": \"The label used by the button on the collapsible TOC component\"\n  },\n  \"theme.blog.post.readMoreLabel\": {\n    \"message\": \"Read more about {title}\",\n    \"description\": \"The ARIA label for the link to full blog posts from excerpts\"\n  },\n  \"theme.colorToggle.ariaLabel\": {\n    \"message\": \"ダークモードとライトモードを切り替える (現在は {mode})\",\n    \"description\": \"The ARIA label for the color mode toggle\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.dark\": {\n    \"message\": \"ダークモード\",\n    \"description\": \"The name for the dark color mode\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.light\": {\n    \"message\": \"ライトモード\",\n    \"description\": \"The name for the light color mode\"\n  },\n  \"theme.docs.versionBadge.label\": {\n    \"message\": \"Version: {versionLabel}\"\n  },\n  \"theme.navbar.mobileLanguageDropdown.label\": {\n    \"message\": \"Languages\",\n    \"description\": \"The label for the mobile language switcher dropdown\"\n  },\n  \"theme.docs.breadcrumbs.home\": {\n    \"message\": \"Home page\",\n    \"description\": \"The ARIA label for the home page in the breadcrumbs\"\n  },\n  \"theme.docs.breadcrumbs.navAriaLabel\": {\n    \"message\": \"Breadcrumbs\",\n    \"description\": \"The ARIA label for the breadcrumbs\"\n  },\n  \"theme.CodeBlock.wordWrapToggle\": {\n    \"message\": \"Toggle word wrap\",\n    \"description\": \"The title attribute for toggle word wrapping button of code block lines\"\n  },\n  \"theme.SearchBar.seeAll\": {\n    \"message\": \"See all results\"\n  },\n  \"theme.SearchBar.label\": {\n    \"message\": \"検索\",\n    \"description\": \"The ARIA label and placeholder for search button\"\n  },\n  \"theme.SearchPage.existingResultsTitle\": {\n    \"message\": \"Search results for \\\"{query}\\\"\",\n    \"description\": \"The search page title for non-empty query\"\n  },\n  \"theme.SearchPage.emptyResultsTitle\": {\n    \"message\": \"Search the documentation\",\n    \"description\": \"The search page title for empty query\"\n  },\n  \"theme.SearchPage.documentsFound.plurals\": {\n    \"message\": \"1 document found|{count} documents found\",\n    \"description\": \"Pluralized label for \\\"{count} documents found\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.SearchPage.noResultsText\": {\n    \"message\": \"見つかりませんでした。\",\n    \"description\": \"The paragraph for empty search result\"\n  },\n  \"theme.admonition.note\": {\n    \"message\": \"note\",\n    \"description\": \"The default label used for the Note admonition (:::note)\"\n  },\n  \"theme.admonition.tip\": {\n    \"message\": \"tip\",\n    \"description\": \"The default label used for the Tip admonition (:::tip)\"\n  },\n  \"theme.admonition.danger\": {\n    \"message\": \"danger\",\n    \"description\": \"The default label used for the Danger admonition (:::danger)\"\n  },\n  \"theme.admonition.info\": {\n    \"message\": \"info\",\n    \"description\": \"The default label used for the Info admonition (:::info)\"\n  },\n  \"theme.admonition.caution\": {\n    \"message\": \"注意\",\n    \"description\": \"The default label used for the Caution admonition (:::caution)\"\n  },\n  \"theme.tags.tagsPageTitle\": {\n    \"message\": \"タグ\",\n    \"description\": \"The title of the tag list page\"\n  },\n  \"theme.NavBar.navAriaLabel\": {\n    \"message\": \"Main\",\n    \"description\": \"The ARIA label for the main navigation\"\n  },\n  \"theme.docs.sidebar.navAriaLabel\": {\n    \"message\": \"Docs sidebar\",\n    \"description\": \"The ARIA label for the sidebar navigation\"\n  },\n  \"theme.docs.sidebar.closeSidebarButtonAriaLabel\": {\n    \"message\": \"Close navigation bar\",\n    \"description\": \"The ARIA label for close button of mobile sidebar\"\n  },\n  \"theme.docs.sidebar.toggleSidebarButtonAriaLabel\": {\n    \"message\": \"Toggle navigation bar\",\n    \"description\": \"The ARIA label for hamburger menu button of mobile navigation\"\n  },\n  \"theme.admonition.warning\": {\n    \"message\": \"警告\",\n    \"description\": \"The default label used for the Warning admonition (:::warning)\"\n  },\n  \"theme.DocSidebarItem.expandCategoryAriaLabel\": {\n    \"message\": \"Expand sidebar category '{label}'\",\n    \"description\": \"The ARIA label to expand the sidebar category\"\n  },\n  \"theme.DocSidebarItem.collapseCategoryAriaLabel\": {\n    \"message\": \"Collapse sidebar category '{label}'\",\n    \"description\": \"The ARIA label to collapse the sidebar category\"\n  },\n  \"theme.SearchPage.inputPlaceholder\": {\n    \"message\": \"検索するキーワードを入力してください\",\n    \"description\": \"The placeholder for search page input\"\n  },\n  \"theme.SearchPage.inputLabel\": {\n    \"message\": \"検索\",\n    \"description\": \"The ARIA label for search page input\"\n  },\n  \"theme.SearchPage.algoliaLabel\": {\n    \"message\": \"Algoliaで検索\",\n    \"description\": \"The description label for Algolia mention\"\n  },\n  \"theme.SearchPage.fetchingNewResults\": {\n    \"message\": \"新しい検索結果を取得しています...\",\n    \"description\": \"The paragraph for fetching new search results\"\n  },\n  \"theme.SearchModal.searchBox.resetButtonTitle\": {\n    \"message\": \"クリア\",\n    \"description\": \"The label and ARIA label for search box reset button\"\n  },\n  \"theme.SearchModal.searchBox.cancelButtonText\": {\n    \"message\": \"キャンセル\",\n    \"description\": \"The label and ARIA label for search box cancel button\"\n  },\n  \"theme.SearchModal.startScreen.recentSearchesTitle\": {\n    \"message\": \"最近の検索\",\n    \"description\": \"The title for recent searches\"\n  },\n  \"theme.SearchModal.startScreen.noRecentSearchesText\": {\n    \"message\": \"最近の検索履歴はありません\",\n    \"description\": \"The text when there are no recent searches\"\n  },\n  \"theme.SearchModal.startScreen.saveRecentSearchButtonTitle\": {\n    \"message\": \"この検索をお気に入りに追加\",\n    \"description\": \"The title for save recent search button\"\n  },\n  \"theme.SearchModal.startScreen.removeRecentSearchButtonTitle\": {\n    \"message\": \"この検索を履歴から削除\",\n    \"description\": \"The title for remove recent search button\"\n  },\n  \"theme.SearchModal.startScreen.favoriteSearchesTitle\": {\n    \"message\": \"お気に入り\",\n    \"description\": \"The title for favorite searches\"\n  },\n  \"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle\": {\n    \"message\": \"この検索をお気に入りから削除\",\n    \"description\": \"The title for remove favorite search button\"\n  },\n  \"theme.SearchModal.errorScreen.titleText\": {\n    \"message\": \"検索結果の取得に失敗しました\",\n    \"description\": \"The title for error screen\"\n  },\n  \"theme.SearchModal.errorScreen.helpText\": {\n    \"message\": \"ネットワーク接続を確認してください\",\n    \"description\": \"The help text for error screen\"\n  },\n  \"theme.SearchModal.footer.selectText\": {\n    \"message\": \"選ぶ\",\n    \"description\": \"The select text for footer\"\n  },\n  \"theme.SearchModal.footer.selectKeyAriaLabel\": {\n    \"message\": \"エンターキー\",\n    \"description\": \"The ARIA label for select key in footer\"\n  },\n  \"theme.SearchModal.footer.navigateText\": {\n    \"message\": \"移動\",\n    \"description\": \"The navigate text for footer\"\n  },\n  \"theme.SearchModal.footer.navigateUpKeyAriaLabel\": {\n    \"message\": \"上矢印キー\",\n    \"description\": \"The ARIA label for navigate up key in footer\"\n  },\n  \"theme.SearchModal.footer.navigateDownKeyAriaLabel\": {\n    \"message\": \"下矢印キー\",\n    \"description\": \"The ARIA label for navigate down key in footer\"\n  },\n  \"theme.SearchModal.footer.closeText\": {\n    \"message\": \"閉じる\",\n    \"description\": \"The close text for footer\"\n  },\n  \"theme.SearchModal.footer.closeKeyAriaLabel\": {\n    \"message\": \"エスケープキー\",\n    \"description\": \"The ARIA label for close key in footer\"\n  },\n  \"theme.SearchModal.footer.searchByText\": {\n    \"message\": \"検索\",\n    \"description\": \"The 'Powered by' text for footer\"\n  },\n  \"theme.SearchModal.noResultsScreen.noResultsText\": {\n    \"message\": \"見つかりませんでした\",\n    \"description\": \"The text when there are no results\"\n  },\n  \"theme.SearchModal.noResultsScreen.suggestedQueryText\": {\n    \"message\": \"次の検索を試す:\",\n    \"description\": \"The text for suggested query\"\n  },\n  \"theme.SearchModal.noResultsScreen.reportMissingResultsText\": {\n    \"message\": \"よりよい検索結果がありますか?\",\n    \"description\": \"The text for reporting missing results\"\n  },\n  \"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText\": {\n    \"message\": \"報告する\",\n    \"description\": \"The link text for reporting missing results\"\n  },\n  \"theme.SearchModal.placeholder\": {\n    \"message\": \"ドキュメントを検索\",\n    \"description\": \"The placeholder of the input of the DocSearch pop-up modal\"\n  },\n  \"theme.docs.DocCard.categoryDescription.plurals\": {\n    \"message\": \"{count}項目\",\n    \"description\": \"The default description for a category card in the generated index about how many items this category includes\"\n  },\n  \"theme.blog.author.pageTitle\": {\n    \"message\": \"{authorName} - {nPosts}\",\n    \"description\": \"The title of the page for a blog author\"\n  },\n  \"theme.blog.authorsList.pageTitle\": {\n    \"message\": \"Authors\",\n    \"description\": \"The title of the authors page\"\n  },\n  \"theme.blog.authorsList.viewAll\": {\n    \"message\": \"View All Authors\",\n    \"description\": \"The label of the link targeting the blog authors page\"\n  },\n  \"theme.contentVisibility.unlistedBanner.title\": {\n    \"message\": \"非公開のページ\",\n    \"description\": \"The unlisted content banner title\"\n  },\n  \"theme.contentVisibility.unlistedBanner.message\": {\n    \"message\": \"このページは非公開です。 検索対象外となり、このページのリンクに直接アクセスできるユーザーのみに公開されます。\",\n    \"description\": \"The unlisted content banner message\"\n  },\n  \"theme.contentVisibility.draftBanner.title\": {\n    \"message\": \"下書きページ\",\n    \"description\": \"The draft content banner title\"\n  },\n  \"theme.contentVisibility.draftBanner.message\": {\n    \"message\": \"このページは下書きです。開発環境でのみ表示され、本番ビルドからは除外されます。\",\n    \"description\": \"The draft content banner message\"\n  },\n  \"theme.blog.author.noPosts\": {\n    \"message\": \"この著者による投稿はまだありません。\",\n    \"description\": \"The text for authors with 0 blog post\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.system\": {\n    \"message\": \"システムモード\",\n    \"description\": \"The name for the system color mode\"\n  },\n  \"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel\": {\n    \"message\": \"ドロップダウンを展開\",\n    \"description\": \"The ARIA label of the button to expand the mobile dropdown navbar item\"\n  },\n  \"theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel\": {\n    \"message\": \"ドロップダウンを折りたたむ\",\n    \"description\": \"The ARIA label of the button to collapse the mobile dropdown navbar item\"\n  },\n  \"theme.IconExternalLink.ariaLabel\": {\n    \"message\": \"(opens in new tab)\",\n    \"description\": \"The ARIA label for the external link icon\"\n  },\n  \"theme.SearchModal.searchBox.placeholderText\": {\n    \"message\": \"ドキュメントを検索\",\n    \"description\": \"The placeholder text for the main search input field\"\n  },\n  \"theme.SearchModal.searchBox.placeholderTextAskAi\": {\n    \"message\": \"別の質問をする...\",\n    \"description\": \"The placeholder text when in AI question mode\"\n  },\n  \"theme.SearchModal.searchBox.placeholderTextAskAiStreaming\": {\n    \"message\": \"回答中...\",\n    \"description\": \"The placeholder text for search box when AI is streaming an answer\"\n  },\n  \"theme.SearchModal.searchBox.enterKeyHint\": {\n    \"message\": \"検索\",\n    \"description\": \"The hint for the search box enter key text\"\n  },\n  \"theme.SearchModal.searchBox.enterKeyHintAskAi\": {\n    \"message\": \"確定\",\n    \"description\": \"The hint for the Ask AI search box enter key text\"\n  },\n  \"theme.SearchModal.searchBox.searchInputLabel\": {\n    \"message\": \"検索\",\n    \"description\": \"The ARIA label for search input\"\n  },\n  \"theme.SearchModal.searchBox.backToKeywordSearchButtonText\": {\n    \"message\": \"キーワード検索に戻る\",\n    \"description\": \"The text for back to keyword search button\"\n  },\n  \"theme.SearchModal.searchBox.backToKeywordSearchButtonAriaLabel\": {\n    \"message\": \"キーワード検索に戻る\",\n    \"description\": \"The ARIA label for back to keyword search button\"\n  },\n  \"theme.SearchModal.startScreen.recentConversationsTitle\": {\n    \"message\": \"最近の会話\",\n    \"description\": \"The title for recent conversations\"\n  },\n  \"theme.SearchModal.startScreen.removeRecentConversationButtonTitle\": {\n    \"message\": \"この会話を履歴から削除\",\n    \"description\": \"The title for remove recent conversation button\"\n  },\n  \"theme.SearchModal.resultsScreen.askAiPlaceholder\": {\n    \"message\": \"AIに質問：\",\n    \"description\": \"The placeholder text for Ask AI input\"\n  },\n  \"theme.SearchModal.askAiScreen.disclaimerText\": {\n    \"message\": \"回答はAIによって生成されており、誤りがある可能性があります。必ず内容を確認してください。\",\n    \"description\": \"The disclaimer text for AI answers\"\n  },\n  \"theme.SearchModal.askAiScreen.relatedSourcesText\": {\n    \"message\": \"関連ソース\",\n    \"description\": \"The text for related sources\"\n  },\n  \"theme.SearchModal.askAiScreen.thinkingText\": {\n    \"message\": \"考え中...\",\n    \"description\": \"The text when AI is thinking\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonText\": {\n    \"message\": \"コピー\",\n    \"description\": \"The text for copy button\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonCopiedText\": {\n    \"message\": \"コピーしました！\",\n    \"description\": \"The text for copy button when copied\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonTitle\": {\n    \"message\": \"コピー\",\n    \"description\": \"The title for copy button\"\n  },\n  \"theme.SearchModal.askAiScreen.likeButtonTitle\": {\n    \"message\": \"いいね\",\n    \"description\": \"The title for like button\"\n  },\n  \"theme.SearchModal.askAiScreen.dislikeButtonTitle\": {\n    \"message\": \"よくない\",\n    \"description\": \"The title for dislike button\"\n  },\n  \"theme.SearchModal.askAiScreen.thanksForFeedbackText\": {\n    \"message\": \"フィードバックありがとうございます！\",\n    \"description\": \"The text for thanks for feedback\"\n  },\n  \"theme.SearchModal.askAiScreen.preToolCallText\": {\n    \"message\": \"検索中...\",\n    \"description\": \"The text before tool call\"\n  },\n  \"theme.SearchModal.askAiScreen.duringToolCallText\": {\n    \"message\": \"検索中：\",\n    \"description\": \"The text during tool call\"\n  },\n  \"theme.SearchModal.askAiScreen.afterToolCallText\": {\n    \"message\": \"検索完了：\",\n    \"description\": \"The text after tool call\"\n  },\n  \"theme.SearchModal.footer.submitQuestionText\": {\n    \"message\": \"質問を送信\",\n    \"description\": \"The submit question text for footer\"\n  },\n  \"theme.SearchModal.footer.backToSearchText\": {\n    \"message\": \"検索に戻る\",\n    \"description\": \"The back to search text for footer\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-blog/options.json",
    "content": "{\n  \"title\": {\n    \"message\": \"Yew Blog\",\n    \"description\": \"The title for the blog used in SEO\"\n  },\n  \"description\": {\n    \"message\": \"Blog\",\n    \"description\": \"The description for the blog used in SEO\"\n  },\n  \"sidebar.title\": {\n    \"message\": \"Recent posts\",\n    \"description\": \"The label for the left sidebar\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/children.mdx",
    "content": "---\ntitle: '子コンポーネント'\n---\n\n:::caution\n\n`Children` をチェックおよび操作すると、アプリケーションで驚くべきかつ説明が難しい動作が発生することがよくあります。これにより、エッジケースが発生し、通常は予期しない結果が生じる可能性があります。`Children` を操作しようとする場合は、他の方法を検討する必要があります。\n\nYew は、子コンポーネントのプロパティの型として `Html` を使用することをサポートしています。`Children` または `ChildrenRenderer` が必要ない場合は、子コンポーネントとして `Html` を使用することをお勧めします。これは `Children` の欠点がなく、パフォーマンスのオーバーヘッドも低くなります。\n\n:::\n\n## 一般的な使用法\n\n_ほとんどの場合、_ コンポーネントに子コンポーネントを持たせる場合、子コンポーネントの型を気にする必要はありません。この場合、以下の例で十分です。\n\n````rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n\n## 高度な使用法\n\n### 型指定された子コンポーネント\n\n特定のタイプのコンポーネントを子コンポーネントとして渡したい場合は、`yew::html::ChildrenWithProps<T>` を使用できます。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n````\n\n## プロパティを持つネストされた子コンポーネント\n\nコンポーネントがその子コンポーネントを型指定している場合、ネストされたコンポーネントのプロパティにアクセスして変更することができます。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 列挙型の子コンポーネント\n\nもちろん、時には子コンポーネントをいくつかの異なるコンポーネントに制限する必要がある場合があります。そのような場合には、Yewについてさらに深く理解する必要があります。\n\nここでは、より良いエルゴノミクスを提供するために [`derive_more`](https://github.com/JelteF/derive_more) を使用しています。使用したくない場合は、各バリアントに対して手動で `From` を実装することができます。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 現在、`Into<Html>` を実装して、yew が `Item` をどのようにレンダリングするかを知ることができるようにします。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### オプションの型の子コンポーネント\n\n特定の型の単一のオプションの子コンポーネントを持つこともできます：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... ページ内容\n            </div>\n        }\n    }\n}\n\n// ページコンポーネントはサイドバーを含むかどうかを選択できます：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // サイドバーを含むページ\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // サイドバーを含まないページ\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## さらに読む\n\n- このパターンの実際の例については、yew-router のソースコードを参照してください。より高度な例については、yew リポジトリの[関連する例のリスト](https://github.com/yewstack/yew/tree/master/examples/nested_list)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '仕組み'\ndescription: 'フレームワークの低レベルの詳細について'\n---\n\n# 基本ライブラリの内部詳細\n\n## `html!` マクロの内部\n\n`html!` マクロは、HTMLに似たカスタム構文で記述されたコードを有効なRustコードに変換します。このマクロを使用することはYewアプリケーションの開発に必須ではありませんが、推奨されています。このマクロが生成するコードはYewのパブリックライブラリAPIを使用しており、希望すれば直接使用することもできます。いくつかのメソッドは意図的に文書化されていないため、誤用を避けるために注意が必要です。`yew-macro`の各更新により、生成されるコードはより効率的になり、`html!`構文をほとんど（または全く）変更することなく破壊的な変更を処理できるようになります。\n\n`html!` マクロを使用すると、宣言的なスタイルでコードを記述できるため、UIレイアウトコードはページのHTMLに非常に似たものになります。アプリケーションがよりインタラクティブになり、コードベースが大きくなるにつれて、この方法はますます有用になります。DOM 操作のすべてのコードを手動で記述するのに比べて、マクロがこれらすべてを処理してくれます。\n\n`html!` マクロの使用は非常に魔法のように感じるかもしれませんが、隠すべきものは何もありません。その仕組みに興味がある場合は、プログラム内の `html!` マクロ呼び出しを展開してみてください。`cargo expand` という便利なコマンドがあり、Rustマクロの展開を確認できます。`cargo expand` はデフォルトで `cargo` に含まれていないため、まだインストールしていない場合は `cargo install cargo-expand` を使用してインストールする必要があります。[Rust-Analyzer](https://rust-analyzer.github.io/) も[IDEからマクロ出力を取得するメカニズム](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)を提供しています。\n\n`html!` マクロの出力は通常非常に簡潔です！これは特徴です：機械生成のコードは時々アプリケーション内の他のコードと衝突することがあります。問題を防ぐために、`proc_macro` は「衛生」ルールに従っています。いくつかの例を以下に示します：\n\n1. Yewパッケージを正しく参照するために、マクロ生成コードでは `::yew::<module>` を使用し、直接 `yew::<module>` を使用しません。これは `::alloc::vec::Vec::new()` を呼び出すのと同じ理由です。\n2. トレイトメソッド名の衝突を避けるために、`<Type as Trait>` を使用して正しいトレイトメンバーを使用していることを確認します。\n\n## 仮想 DOM とは？\n\nDOM（「ドキュメントオブジェクトモデル」）は、ブラウザによって管理されるHTMLコンテンツの表現です。「仮想」 DOM は、単にメモリ内の DOM のコピーです。仮想 DOM を管理することで、メモリのオーバーヘッドが増加しますが、ブラウザAPIの使用を回避または遅延させることでバッチ処理と高速な読み取りを実現できます。\n\nメモリ内に DOM のコピーを持つことは、宣言的UIを使用するライブラリの使用を促進するのに役立ちます。ユーザーイベントに基づいて DOM を変更するための特定のコードが必要な場合とは異なり、ライブラリは一般的な方法を使用して DOM の「差分」を行うことができます。Yewコンポーネントが更新され、そのレンダリング方法を変更したい場合、Yewライブラリは仮想 DOM の2番目のコピーを構築し、現在画面上に表示されている内容をミラーリングする仮想 DOM と直接比較します。両者の「差分」は増分更新に分解され、ブラウザAPIと共に適用されます。更新が適用されると、古い仮想 DOM のコピーは破棄され、新しいコピーが将来の差分チェックのために保存されます。\n\nこの「差分」アルゴリズムは、時間の経過とともに最適化され、複雑なアプリケーションのパフォーマンスを向上させることができます。YewアプリケーションはWebAssemblyを介して実行されるため、Yewは将来的により複雑なアルゴリズムを採用する上で競争力を持つと信じています。\n\nYewの仮想 DOM はブラウザの DOM と完全に一対一対応しているわけではありません。DOM 要素を整理するための「リスト」や「コンポーネント」も含まれています。リストは単に要素の順序付きリストである場合もありますが、より強力な場合もあります。各リスト要素に「キー」注釈を追加することで、アプリケーション開発者はリストが変更されたときに差分更新の計算に必要な作業量を最小限に抑えるための追加の最適化をYewに提供できます。同様に、コンポーネントは再レンダリングが必要かどうかを示すカスタムロジックを提供し、パフォーマンスを向上させるのに役立ちます。\n\n## Yewスケジューラとコンポーネントスコープのイベントループ\n\n_貢献ドキュメント - `yew::scheduler` と `yew::html::scope` の仕組みを詳しく説明_\n\n## さらなる読み物\n\n- [Rustのマクロに関する詳細情報](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` に関する詳細情報](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` のAPIドキュメント](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'イミュータブルタイプ'\ndescription: 'Yew のイミュータブルデータ構造'\n---\n\n## イミュータブルタイプとは？\n\nこれらのタイプは、インスタンス化はできるが値を変更することはできないタイプです。値を更新するには、新しい値をインスタンス化する必要があります。\n\n## なぜイミュータブルタイプを使用するのですか？\n\nReact と同様に、プロパティは祖先から子孫に伝播されます。これは、各コンポーネントが更新されるたびにプロパティが存在する必要があることを意味します。したがって、プロパティは理想的には簡単にクローンできるべきです。これを実現するために、通常は `Rc` にラップします。\n\nイミュータブルタイプは、コンポーネント間でプロパティの値を低コストでクローンできるため、プロパティの値を保持するのに最適です。\n\n## 一般的なイミュータブルタイプ\n\nYew は `implicit-clone` クレートから以下のイミュータブルタイプの使用を推奨しています：\n\n- `IString`（Yew では `AttrValue` としてエイリアス化）- `String` の代わりに文字列用\n- `IArray<T>` - `Vec<T>` の代わりに配列・ベクター用\n- `IMap<K, V>` - `HashMap<K, V>` の代わりにマップ用\n\nこれらのタイプは参照カウント（`Rc`）または静的参照のいずれかであり、非常に安価にクローンできます。\n\n## さらに読む\n\n- [イミュータブルの例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '最適化とベストプラクティス'\nsidebar_label: Optimizations\ndescription: 'アプリケーションのパフォーマンスを最適化する'\n---\n\n## スマートポインタの使用\n\n**注意：このセクションで使用されている用語に混乱がある場合は、Rustのマニュアルにある[スマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)が役立ちます。**\n\n再レンダリング時に大量のデータをクローンしてpropsを作成するのを避けるために、スマートポインタを使用してデータ自体ではなくデータへの参照のみをクローンすることができます。propsや子コンポーネントに関連データの参照を渡すことで、データを変更する必要がある子コンポーネントでデータをクローンするのを避けることができます。`Rc::make_mut`を使用してデータをクローンし、変更するための可変参照を取得できます。\n\nこれにより、`Component::changed`でのpropの変更がコンポーネントの再レンダリングを必要とするかどうかを判断する際にさらに利点があります。これは、データの値ではなくポインタのアドレス（つまり、データがマシンメモリに格納されている場所）を比較できるためです。2つのポインタが同じデータを指している場合、それらが指しているデータの値は同じでなければなりません。逆は必ずしも真ではないことに注意してください！2つのポインタアドレスが異なる場合でも、基になるデータは同じである可能性があります。この場合、基になるデータを比較する必要があります。\n\nこの比較を行うには、`PartialEq`（データを比較する際に自動的に使用される等価演算子`==`）ではなく、`Rc::ptr_eq`を使用する必要があります。Rustのドキュメントには、`Rc::ptr_eq`に関する[詳細](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)があります。\n\nこの最適化は、`Copy`を実装していないデータ型に最も有用です。データを安価にコピーできる場合、それをスマートポインタの後ろに置く必要はありません。`Vec`、`HashMap`、`String`などのデータ集約型の構造体に対して、スマートポインタを使用することでパフォーマンスの向上が見込まれます。\n\nこの最適化は、子コンポーネントが値を更新しない場合に最も効果的であり、親コンポーネントがほとんど更新されない場合にさらに効果的です。これにより、`Rc<_>`は純粋なコンポーネントでpropsの値をラップするのに適した選択肢となります。\n\nただし、子コンポーネントでデータを自分でクローンする必要がない限り、この最適化は無駄であり、不要な参照カウントのコストを追加するだけです。Yewのpropsはすでに参照カウントされており、内部でデータのクローンは行われません。\n\n## レンダリング関数\n\nコードの可読性のために、`html!`の一部の繰り返しコードを専用の分割関数に移行することは通常意味があります。これにより、コードが読みやすくなり、インデントが減り、良いデザインパターンを奨励します。特に、複数の場所で呼び出すことができるこれらの関数を使用して、コード量を減らすことができます。\n\n## 純粋なコンポーネント\n\n純粋なコンポーネントは、その状態を変更せず、コンテンツを表示し、メッセージを通常の可変コンポーネントに伝播するコンポーネントです。これらは、`html!`マクロ内でコンポーネント構文（`<SomePureComponent />`）を使用する点でビュー関数とは異なり、実装に応じてメモ化される可能性があります（これは、一度関数が呼び出されると、その値が「保存」されることを意味し、同じパラメータで複数回呼び出された場合、その値を再計算する必要がなく、最初の関数呼び出しから保存された値を返すだけです）。Yewは内部でpropsを比較するため、propsが変更された場合にのみUIを再レンダリングします。\n\n## ワークスペースを使用してコンパイル時間を短縮する\n\nYewの最大の欠点は、コンパイルにかかる時間が長いことです。プロジェクトのコンパイルにかかる時間は、`html!`マクロに渡されるコードの量に関連しているようです。小規模なプロジェクトでは問題にならないようですが、大規模なアプリケーションでは、コンパイラがアプリケーションのために行う作業量を最小限に抑えるためにコードを複数のクレートに分割することが理にかなっています。\n\n1つの方法として、メインクレートがルーティング/ページ選択を処理し、各ページごとに異なるクレートを作成することが考えられます。各ページは異なるコンポーネントまたは`Html`を生成する大きな関数である可能性があります。アプリケーションの異なる部分を含むクレート間で共有されるコードは、プロジェクトが依存する別のクレートに格納できます。理想的には、すべてのコードを再コンパイルするのではなく、メインクレートと1つのページクレートのみを再コンパイルすることになります。最悪の場合、「共通」クレートで何かを編集した場合、すべての依存コードを再コンパイルする必要があり、元の状態に戻ります。\n\nメインクレートが重すぎる場合や、深くネストされたページ（例：別のページ上にレンダリングされるページ）を迅速に反復したい場合は、メインページの簡略化された実装を作成し、作業中のコンポーネントを追加でレンダリングするためにサンプルクレートを使用できます。\n\n## バイナリサイズの縮小\n\n- Rustコードの最適化\n- `cargo.toml`（リリースプロファイルの定義）\n- `wasm-opt` を使用してwasmコードを最適化\n\n**注意：バイナリサイズの縮小に関する詳細は、[Rust Wasmマニュアル](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)を参照してください。**\n\n### Cargo.toml\n\nリリースビルドをより小さくするために、`Cargo.toml`の`[profile.release]`セクションで利用可能な設定を使用して構成できます。\n\n```toml, title=Cargo.toml\n[profile.release]\n# バイナリサイズを小さくする\npanic = 'abort'\n# コード全体を最適化する（最適化は良くなるが、ビルド速度は遅くなる）\ncodegen-units = 1\n# サイズを最適化する（より積極的なアプローチ）\nopt-level = 'z'\n# サイズを最適化する\n# opt-level = 's'\n# プログラム全体の解析を使用してリンク時に最適化\nlto = true\n```\n\n### 開発版 Cargo 設定\n\nRust と cargo の実験的な開発版機能から追加の利点を得ることもできます。`trunk` の開発版ツールチェーンを使用するには、`RUSTUP_TOOLCHAIN=\"nightly\"` 環境変数を設定します。その後、`.cargo/config.toml` で不安定な rustc 機能を構成できます。不安定機能のドキュメント、特に[`build-std`]および[`build-std-features`]に関する部分を参照して、設定方法を確認してください。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# rust-srcコンポーネントが必要です。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不安定な機能のリスト]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n開発版のRustコンパイラには、[この例](https://github.com/yewstack/yew/issues/2696)のようなバグが含まれている可能性があるため、定期的に監視し調整する必要があります。これらの実験的なオプションを使用する際は注意が必要です。\n:::\n\n### wasm-opt\n\nさらに、`wasm` コードのサイズを最適化することができます。\n\nRust Wasm マニュアルには、Wasm バイナリファイルのサイズを縮小する方法に関するセクションがあります：[.wasm サイズの縮小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- `wasm-pack` を使用すると、デフォルトでリリースビルドの `wasm` コードが最適化されます\n- `wasm` ファイルに直接 `wasm-opt` を使用する\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### yew/examples/ の 'minimal' サンプルのビルドサイズ\n\n注意：`wasm-pack` は Rust と Wasm コードの最適化を組み合わせています。この例では、`wasm-bindgen` は Rust のサイズ最適化を行っていません。\n\n| ツールチェーン              | サイズ |\n| :-------------------------- | :----- |\n| wasm-bindgen                | 158KB  |\n| wasm-bindgen + wasm-opt -Os | 116KB  |\n| wasm-pack                   | 99 KB  |\n\n## さらに読む\n\n- [Rust マニュアルのスマート ポインターに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm マニュアルのコードサイズの縮小に関する章](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust プロファイルに関するドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'ポータル (Portals)'\ndescription: 'コンテンツをDOMツリー外のノードにレンダリングする'\n---\n\n## ポータルとは？\n\nポータル (Portal) は、子要素を親コンポーネントのDOM階層外のDOMノードにレンダリングする方法を提供します。`yew::create_portal(child, host)` は `Html` 値を返し、`child` を `host` 要素の子要素としてレンダリングしますが、親コンポーネントの階層下ではありません。\n\n## 使用方法\n\nポータルの典型的な用途には、モーダルダイアログやホバーカード、さらに技術的な用途として、要素の [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) の内容を制御すること、スタイルシートを周囲のドキュメントの `<head>` に添付すること、`<svg>` の中央の `<defs>` 要素に参照される要素を収集することなどがあります。\n\n`yew::create_portal` は低レベルの構成要素であることに注意してください。ライブラリはこれを使用してより高レベルのAPIを実装し、その後アプリケーションはこれらのAPIを使用できます。例えば、ここでは `children` を `yew` 以外の要素にレンダリングするシンプルなモーダルダイアログを示します。この要素は `id=\"modal_host\"` で識別されます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## イベント処理\n\nポータル内部の要素で発生するイベントは、仮想DOMのバブリングに従います。つまり、ポータルが要素の子要素としてレンダリングされる場合、その要素上のイベントリスナーは、ポータル内部から発生するイベントをキャプチャします。たとえポータルが実際のDOM内の無関係な位置にその内容をレンダリングしていてもです。\n\nこれにより、開発者は使用しているコンポーネントがポータルを使用して実装されているかどうかを気にする必要がなくなります。いずれにせよ、その子要素上で発生するイベントはバブリングします。\n\n既知の問題として、ポータルから **閉じた** シャドウルートへのイベントは2回分配されます。1回はシャドウルート内部の要素に対して、もう1回はホスト要素自体に対してです。**開いた** シャドウルートは正常に動作しますので、これが影響する場合は、いつでもバグレポートを提出してください。\n\n## さらなる読み物\n\n- [ポータルの例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: 'サーバーサイドレンダリング'\ndescription: 'Yewコンポーネントをサーバーサイドでレンダリングする。'\n---\n\n# サーバーサイドレンダリング (Server-Side Rendering)\n\nデフォルトでは、Yewコンポーネントはクライアントサイドでレンダリングされます。ユーザーがウェブサイトにアクセスすると、サーバーは実際のコンテンツを含まない骨組みのHTMLファイルとWebAssemblyパッケージをブラウザに送信します。すべてのコンテンツはクライアントサイドでWebAssemblyパッケージによってレンダリングされます。これをクライアントサイドレンダリングと呼びます。\n\nこの方法はほとんどのウェブサイトにとって有効ですが、いくつかの注意点があります：\n\n1. ユーザーはWebAssemblyパッケージがダウンロードされ、初期レンダリングが完了するまで何も表示されません。これにより、ネットワークが遅い場合にユーザーエクスペリエンスが悪化する可能性があります。\n2. 一部の検索エンジンは動的にレンダリングされたウェブページのコンテンツをサポートしておらず、サポートしている検索エンジンでも通常は動的なウェブサイトのランキングが低くなります。\n\nこれらの問題を解決するために、ウェブサイトをサーバーサイドでレンダリングすることができます。\n\n## 動作原理\n\nYewはページをサーバーサイドでレンダリングするための `ServerRenderer` を提供しています。\n\nYewコンポーネントをサーバーサイドでレンダリングするには、`ServerRenderer::<App>::new()` を使用してレンダラーを作成し、`renderer.render().await` を呼び出して `<App />` を `String` としてレンダリングします。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// この例が CI の WASM 環境で動作することを保証するために `flavor = \"current_thread\"` を使用しています。\n// マルチスレッドを使用したい場合は、デフォルトの `#[tokio::main]` マクロを使用できます。\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // プリント: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## コンポーネントのライフサイクル\n\nクライアントサイドレンダリングとは異なり、サーバーサイドレンダリング時のコンポーネントのライフサイクルは異なります。\n\nコンポーネントが最初に `Html` として正常にレンダリングされるまで、`use_effect`（および `use_effect_with`）以外のすべてのフックは正常に動作します。\n\n:::caution ブラウザインターフェースは利用できません！\n\n`web_sys` などのブラウザ関連のインターフェースは、サーバーサイドレンダリング時には利用できません。これらを使用しようとすると、アプリケーションがクラッシュします。このロジックは `use_effect` または `use_effect_with` に隔離する必要があります。これらはサーバーサイドレンダリング時には実行されないためです。\n\n:::\n\n:::danger 構造化コンポーネント\n\nサーバーサイドレンダリング時に構造化コンポーネントを使用することは可能ですが、クライアントサイドの安全なロジック（関数コンポーネントの `use_effect` フックなど）とライフサイクルイベントの間には明確な境界がなく、ライフサイクルイベントの呼び出し順序もクライアントとは異なります。\n\nさらに、構造化コンポーネントは、すべての子コンポーネントがレンダリングされ `destroy` メソッドが呼び出されるまでメッセージを受け取り続けます。開発者は、コンポーネントに渡される可能性のあるメッセージがブラウザインターフェースを呼び出すロジックにリンクされないようにする必要があります。\n\nサーバーサイドレンダリングをサポートするアプリケーションを設計する際は、特別な理由がない限り、関数コンポーネントを使用することをお勧めします。\n\n:::\n\n## サーバーサイドレンダリング中のデータ取得\n\nデータ取得はサーバーサイドレンダリングとハイドレーション（hydration）中の難点の一つです。\n\n従来の方法では、コンポーネントがレンダリングされるとすぐに利用可能になります（仮想DOMを出力してレンダリングします）。コンポーネントがデータを取得する必要がない場合、この方法は有効です。しかし、コンポーネントがレンダリング時にデータを取得しようとするとどうなるでしょうか？\n\n以前は、Yewにはコンポーネントがまだデータを取得しているかどうかを検出するメカニズムがありませんでした。データ取得クライアントは、初期レンダリング中に何が要求されたかを検出し、要求が完了した後に再レンダリングをトリガーするソリューションを実装する責任がありました。サーバーはこのプロセスを繰り返し、応答を返す前にレンダリング中に追加の保留中の要求がないことを確認します。\n\nこれは、コンポーネントを繰り返しレンダリングするため、CPUリソースを浪費するだけでなく、データクライアントは、サーバー側で取得したデータをハイドレーション中に利用可能にする方法を提供する必要があり、初期レンダリングで返される仮想DOMがサーバーサイドレンダリングのDOMツリーと一致することを保証する必要があります。これは実現が難しい場合があります。\n\nYewは、`<Suspense />` を使用してこの問題を解決する異なるアプローチを採用しています。\n\n`<Suspense />` は特別なコンポーネントで、クライアント側で使用する場合、コンポーネントがデータを取得（保留）している間にフォールバックUIを表示し、データ取得が完了した後に通常のUIに戻る方法を提供します。\n\nアプリケーションがサーバーサイドレンダリングされると、Yewはコンポーネントが保留状態でなくなるまで待機し、それを文字列バッファにシリアル化します。\n\nハイドレーション中、`<Suspense />` コンポーネント内の要素は、すべての子コンポーネントが保留状態でなくなるまでハイドレーションされません。\n\nこの方法により、開発者はサーバーサイドレンダリングに対応したクライアント非依存のアプリケーションを簡単に構築し、データ取得を行うことができます。\n\n## `<head>` タグのレンダリング\n\nSSR でよく必要とされるのは、クローラーやソーシャルプレビューが最初のロード時に正しいメタデータを参照できるよう、動的な `<head>` コンテンツ（`<title>`、`<meta>` など）をレンダリングすることです。\n\n`ServerRenderer` はコンポーネントツリー（通常はドキュメントの body 部分）のみをレンダリングし、`<head>` にはアクセスできません。そのため、head タグは **Yew の外部でサーバー側に**生成し、クライアントに送信する前に HTML テンプレートに埋め込む必要があります。\n\n[`ssr_router` サンプル](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) はこのパターンを示しています：サーバーはリクエスト URL からルートを判別し、適切な `<title>` および `<meta>` タグを生成して、Trunk が生成した `index.html` の `</head>` の前に挿入します。\n\n:::info\n\n完全に SSR 互換のサードパーティソリューションとして、[Bounce の `<Helmet/>` コンポーネント](https://docs.rs/bounce/latest/bounce/helmet/index.html) が利用できます。\n\n:::\n\n## サーバーサイドレンダリングハイドレーション（SSR Hydration）\n\nハイドレーションは、Yewアプリケーションをサーバー側で生成されたHTMLファイルに接続するプロセスです。デフォルトでは、`ServerRender` はハイドレーション可能なHTML文字列を出力し、追加情報を含んでハイドレーションを容易にします。`Renderer::hydrate` メソッドを呼び出すと、Yewは最初からレンダリングするのではなく、アプリケーションが生成した仮想DOMとサーバーレンダラーが生成したHTML文字列を調整します。\n\n:::caution\n\n`ServerRenderer` が作成したHTMLマークアップを正常にハイドレーションするためには、クライアントはSSRに使用されたレイアウトと完全に一致する仮想DOMレイアウトを生成する必要があります。要素を含まないコンポーネントも含めてです。特定の実装でのみ使用されるコンポーネントがある場合は、`PhantomComponent` を使用して追加のコンポーネントの位置を埋めることを検討してください。\n:::\n\n:::warning\n\nSSR出力（静的HTML）をブラウザが初期レンダリングした後、実際のDOMが期待されるDOMと一致する場合にのみ、ハイドレーションは成功します。HTMLが規格に準拠していない場合、ハイドレーションは失敗する可能性があります。ブラウザは不正なHTMLのDOM構造を変更する可能性があり、実際のDOMが期待されるDOMと異なることがあります。例えば、[`<tbody>` のない `<table>` がある場合、ブラウザはDOMに `<tbody>` を追加する可能性があります](https://github.com/yewstack/yew/issues/2684)。\n:::\n\n## ハイドレーション中のコンポーネントライフサイクル\n\nハイドレーション中、コンポーネントは作成後に2回連続してレンダリングされます。すべてのエフェクトは2回目のレンダリングが完了した後に呼び出されます。コンポーネントのレンダリング関数に副作用がないことを確認することが重要です。状態を変更したり、追加のレンダリングをトリガーしたりしないようにしてください。現在、状態を変更したり追加のレンダリングをトリガーしたりするコンポーネントがある場合は、それらを `use_effect` フックに移動してください。\n\nハイドレーション中、構造化コンポーネントを使用してサーバーサイドレンダリングを行うことができます。ビュー関数はレンダリング関数の前に複数回呼び出されます。レンダリング関数が呼び出されるまで、DOMは未接続と見なされ、`rendered()` メソッドが呼び出される前にレンダリングノードにアクセスすることを防ぐ必要があります。\n\n## 例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // body 要素の下のすべてのコンテンツをハイドレーションし、末尾の要素を削除します（存在する場合）。\n    renderer.hydrate();\n}\n```\n\n例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## シングルスレッドモード\n\nYewは `yew::LocalServerRenderer` を使用してシングルスレッドでのサーバーサイドレンダリングをサポートしています。このモードはWASIのようなシングルスレッド環境に適しています。\n\n```rust\n// `wasm32-wasip1` または `wasm32-wasip2` ターゲットを使用してビルドしてください。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n`wasm32-unknown-unknown` ターゲットを使用してSSRアプリケーションをビルドする場合、`not_browser_env` 機能フラグを使用して、Yew内部のブラウザ固有のAPIへのアクセスを無効にすることができます。これは、Cloudflare Workerのようなサーバーレスプラットフォームで非常に便利です。\n:::\n\n:::caution\n\nサーバーサイドレンダリングは現在実験的な機能です。バグを見つけた場合は、[GitHubで報告してください](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'コールバック関数 (Callbacks)'\n---\n\n## コールバック関数 (Callbacks)\n\nコールバック関数は、Yew でサービス、エージェント、および親コンポーネントと通信するために使用されます。内部的には、それらの型は `Rc` に包まれた `Fn` に過ぎず、クローンを許可します。\n\nそれらには `emit` 関数があり、その `<IN>` 型を引数として取り、それをターゲットが期待するメッセージに変換します。親コンポーネントのコールバック関数が子コンポーネントに props として提供される場合、子コンポーネントはその `update` ライフサイクルフックでコールバック関数の `emit` 関数を呼び出して、メッセージを親コンポーネントに送信できます。`html!` マクロで props として提供されるクロージャまたは関数は、自動的にコールバック関数に変換されます。\n\nシンプルなコールバック関数の使用例は次のようになります：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nこの関数を `callback` に渡す場合、常に1つの引数を持つ必要があります。例えば、`onclick` ハンドラは `MouseEvent` 型の引数を受け取る関数である必要があります。その後、ハンドラはコンポーネントにどのタイプのメッセージを送信するかを決定できます。このメッセージは無条件に次の更新サイクルにスケジュールされます。\n\n更新を引き起こす必要がないコールバック関数が必要な場合は、`batch_callback` を使用してください。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 関連例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高階コンポーネント'\n---\n\nいくつかの状況では、構造コンポーネントは特定の機能（例えば Suspense）を直接サポートしていないか、または特定の機能を使用するために大量のボイラープレートコードが必要です（例えば Context）。\n\nこのような場合、高階コンポーネントの関数コンポーネントを作成することをお勧めします。\n\n## 高階コンポーネントの定義\n\n高階コンポーネントは、新しい HTML を追加せず、他のコンポーネントをラップして追加機能を提供するコンポーネントです。\n\n### 例\n\nContext（コンテキスト）フックを使用し、それを構造コンポーネントに渡す例\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '紹介'\ndescription: 'Yew のコンポーネント'\n---\n\n## コンポーネントとは？\n\nコンポーネントは Yew の構成要素です。内部状態を管理し、要素を DOM にレンダリングできます。`Component` トレイトを実装することでコンポーネントを作成します。\n\n## コンポーネントマークアップの作成\n\nYew は仮想 DOM を使用して要素を DOM にレンダリングします。仮想 DOM ツリーは `html!` マクロを使用して構築できます。`html!` の構文は HTML に似ていますが、同じではありません。ルールもより厳格です。また、条件付きレンダリングやイテレータを使用したリストのレンダリングなどの強力な機能も提供します。\n\n:::info\n[`html!` マクロ、その使用方法、および構文についてさらに詳しく知る](concepts/html/introduction.mdx)\n:::\n\n## コンポーネントにデータを渡す\n\nYew コンポーネントは _props_ を使用して親コンポーネントと子コンポーネント間で通信します。親コンポーネントは任意のデータを props として子コンポーネントに渡すことができます。Props は HTML 属性に似ていますが、任意の Rust 型を props として渡すことができます。\n\n:::info\n[props についてさらに詳しく知る](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n親/子通信以外の通信には、[コンテキスト](../../concepts/contexts.mdx) を使用してください\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'ライフサイクル'\ndescription: 'コンポーネントとそのライフサイクルフック'\n---\n\n`Component` トレイトには、実装する必要がある多くのメソッドがあります。Yew はコンポーネントのライフサイクルのさまざまな段階でこれらのメソッドを呼び出します。\n\n## ライフサイクル\n\n:::important ドキュメントの改善\n`ドキュメントに貢献する：` [カスタムライフサイクルを持つコンポーネントの例を追加](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## ライフサイクルメソッド\n\n### Create\n\nコンポーネントが作成されるとき、それは親コンポーネントからプロパティを受け取り、それらは `create` メソッドに渡される `Context<Self>` に保存されます。これらのプロパティはコンポーネントの状態を初期化するために使用でき、\"link\" はコールバックを登録したり、コンポーネントにメッセージを送信したりするために使用できます。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体的な実装\n        }\n    }\n}\n```\n\n### View\n\n`view` メソッドは、コンポーネントがDOMにどのようにレンダリングされるべきかを記述することを可能にします。Rust関数を使用してHTMLに似たコードを書くことは非常に混乱する可能性があるため、Yewは`html!`マクロを提供しています。これにより、HTMLおよびSVGノードを宣言し（およびそれらに属性とイベントリスナーを追加し）、子コンポーネントを便利にレンダリングする方法が提供されます。このマクロは、ReactのJSXに似ています（プログラミング言語の違いを除いて）。一つの違いは、YewがSvelteのようなプロパティの簡略化された構文を提供している点です。ここでは、`{onclick}`とだけ書くことができ、`onclick={onclick}`と書く必要はありません。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n使用方法の詳細については、[html! ガイド](concepts/html/introduction.mdx) を参照してください。\n\n### Rendered\n\n`rendered` コンポーネントライフサイクルメソッドは、`view` が呼び出され、Yew がその結果を DOM にレンダリングした後、ブラウザがページを更新する前に呼び出されます。このメソッドは、コンポーネントが要素をレンダリングした後にのみ完了できる操作を実行したい場合に非常に便利です。また、`first_render` という名前のパラメーターがあり、この関数が最初のレンダリング時に呼び出されたか、後続のレンダリング時に呼び出されたかを判断するために使用できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nこのライフサイクルメソッドは実装する必要はなく、デフォルトでは何も実行しません。\n:::\n\n### Update\n\nコンポーネントとの通信は主にメッセージを通じて行われ、これらのメッセージは `update` ライフサイクルメソッドによって処理されます。これにより、コンポーネントはメッセージに基づいて自身を更新し、再レンダリングが必要かどうかを判断できます。メッセージはイベントリスナー、子コンポーネント、エージェント、サービス、またはフューチャーによって送信されることがあります。\n\n以下は `update` の実装例です：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 再レンダリング\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体的な実装\n        }\n    }\n\n}\n```\n\n### Changed\n\nコンポーネントは親コンポーネントによって再レンダリングされることがあります。この場合、新しいプロパティを受け取り、再レンダリングが必要になることがあります。この設計により、プロパティの値を変更するだけで親子コンポーネント間の通信が促進されます。プロパティが変更されると、デフォルトの実装によりコンポーネントが再レンダリングされます。\n\n### Destroy\n\nコンポーネントがDOMからアンマウントされると、Yewは`destroy`ライフサイクルメソッドを呼び出します。コンポーネントが破棄される前にクリーンアップ操作を実行する必要がある場合に便利です。このメソッドはオプションであり、デフォルトでは何も実行しません。\n\n### 無限ループ\n\nYewのライフサイクルメソッドでは無限ループが発生する可能性がありますが、それは各レンダリング後に同じコンポーネントを更新し、その更新が再レンダリングを要求する場合にのみ発生します。\n\n以下は簡単な例です：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // どのメッセージでも常に再レンダリングを要求します\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // レンダリングする内容は重要ではありません\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // この新しいメッセージを使用してコンポーネントを更新するように要求します\n        ctx.link().send_message(());\n    }\n}\n```\n\nここで何が起こっているのか見てみましょう：\n\n1. `create` 関数を使用してコンポーネントを作成します。\n2. `view` メソッドを呼び出して、Yew がブラウザの DOM にレンダリングする内容を知ることができます。\n3. `rendered` メソッドを呼び出し、`Context` リンクを使用して更新メッセージをスケジュールします。\n4. Yew がレンダリングフェーズを完了します。\n5. Yew はスケジュールされたイベントをチェックし、更新メッセージキューが空でないことを確認してメッセージを処理します。\n6. `update` メソッドを呼び出し、変更が発生し、コンポーネントが再レンダリングする必要があることを示す `true` を返します。\n7. ステップ2に戻ります。\n\n`rendered` メソッドで更新をスケジュールすることは依然として可能であり、これは通常便利ですが、その際にはこのループをどのように終了させるかを考慮してください。\n\n## 関連タイプ\n\n`Component` トレイトには、`Message` と `Properties` の2つの関連タイプがあります。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` タイプは、イベントが発生した後にコンポーネントにメッセージを送信するために使用されます。例えば、ユーザーがボタンをクリックしたり、ページをスクロールしたりしたときに何かを実行したい場合があります。コンポーネントは通常、複数のイベントに応答する必要があるため、`Message` タイプは通常、処理するイベントごとにバリアントを持つ列挙型です。\n\nコードベースを整理する際には、`Message` タイプの定義をコンポーネントを定義する同じモジュールに含めるのが賢明です。メッセージタイプの命名に一貫した命名規則を採用することが役立つ場合があります。一つのオプション（唯一のオプションではありませんが）は、タイプを `ComponentNameMsg` と命名することです。例えば、コンポーネントが `Homepage` と名付けられている場合、タイプを `HomepageMsg` と命名することができます。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` は、親コンポーネントからコンポーネントに渡される情報を表します。この型は `Properties` トレイトを実装する必要があり（通常はそれを派生させる）、特定のプロパティが必須かオプションかを指定できます。コンポーネントの作成および更新時にこの型が使用されます。コンポーネントのモジュール内で `Props` という名前の構造体を作成し、それをコンポーネントの `Properties` 型として使用するのが一般的な方法です。通常、\"properties\" は \"props\" と略されます。プロパティは親コンポーネントから渡されるため、アプリケーションのルートコンポーネントは通常、`Properties` 型として `()` を持ちます。ルートコンポーネントにプロパティを指定する場合は、`App::mount_with_props` メソッドを使用します。\n\n:::info\n[プロパティに関する詳細はこちら](./properties)\n:::\n\n## ライフサイクルコンテキスト\n\nすべてのコンポーネントライフサイクルメソッドは、コンテキストオブジェクトを受け取ります。このオブジェクトは、コンポーネントのスコープへの参照を提供し、コンポーネントにメッセージを送信したり、コンポーネントに渡されたプロパティを取得したりすることができます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Props)'\ndescription: '親子コンポーネント間の通信'\n---\n\nプロパティ (Properties) は、子コンポーネントと親コンポーネントの間で通信を可能にします。各コンポーネントには、親コンポーネントから渡される内容を記述するための関連プロパティ型があります。理論的には、これは `Properties` トレイトを実装した任意の型である可能性がありますが、実際には、各フィールドがプロパティを表す構造体であるべきです。\n\n## 派生マクロ\n\n`Properties` トレイトを自分で実装する必要はありません。`#[derive(Properties)]` を使用して実装を自動生成できます。`Properties` を派生する型は `PartialEq` も実装する必要があります。\n\n### フィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。以下の属性を使用すると、他の値が設定されていない限り、プロパティに初期値を提供できます。\n\n:::tip\nプロパティは Rustdoc によって生成されたドキュメントには表示されません。プロパティのドキュメント文字列には、そのプロパティがオプションであるかどうか、または特別なデフォルト値があるかどうかを記載する必要があります。\n:::\n\n#### `#[prop_or_default]`\n\nフィールド型のデフォルト値を使用してプロパティ値を初期化します。これは `Default` トレイトを使用します。\n\n#### `#[prop_or(value)]`\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。\n\n#### `#[prop_or_else(function)]`\n\n`function` を呼び出してプロパティ値を初期化します。`function` は `FnMut() -> T` のシグネチャを持つ必要があります。ここで、`T` はフィールド型です。\n\n## `PartialEq`\n\n`Properties` は `PartialEq` を実装する必要があります。これにより、Yew はそれらを比較し、変更があった場合に `changed` メソッドを呼び出すことができます。\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたポインタに基づいて格納されます。これにより、コンポーネントツリーに渡されるプロパティにはポインタのみが渡され、プロパティ全体をクローンすることによる高価なパフォーマンスオーバーヘッドを回避できます。\n\n:::tip\n`AttrValue` を使用してください。これは、クローンが必要な String やその他の類似の型を使用せずに済むようにするために提供されているカスタムプロパティ値型です。\n:::\n\n## 例\n\n```rust\nuse yew::Properties;\n/// virtual_dom から AttrValue をインポート\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// リンクにはターゲットが必要です\n    href: AttrValue,\n    /// また、String ではなく AttrValue を使用していることに注意してください\n    text: AttrValue,\n    /// リンクの色、デフォルトは `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 値が None の場合、ビュー関数はサイズを指定しません\n    #[prop_or_default]\n    size: Option<u32>,\n    /// ビュー関数がアクティブを指定しない場合、デフォルトは true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、属性や基本式 (`Foo { ..base }`) を使用することはできません。型パスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// リンクにはターゲットが必要です\n    href: AttrValue,\n    /// また、String ではなく AttrValue を使用していることに注意してください\n    text: AttrValue,\n    /// リンクの色、デフォルトは `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 値が None の場合、ビュー関数はサイズを指定しません\n    #[prop_or_default]\n    size: Option<u32>,\n    /// ビュー関数がアクティブを指定しない場合、デフォルトは true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// この関数は href と text を String として受け取ります\n    /// `AttrValue::from` を使用してそれらを `AttrValue` に変換できます\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '参照 (Refs)'\ndescription: 'DOM への越境アクセスを実現する'\n---\n\n`ref` キーワードは、任意の HTML 要素やコンポーネントに使用して、その要素に付随する DOM `Element` を取得できます。これにより、`view` ライフサイクルメソッドの外で DOM を変更することができます。\n\nこれは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。例えば、コンポーネントの `rendered` メソッドで `NodeRef` を使用すると、`view` からレンダリングされた後に canvas 要素に描画呼び出しを行うことができます。\n\n構文は次のとおりです：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 関連例\n\n- [ノード参照](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'スコープ'\ndescription: 'コンポーネントのスコープ'\n---\n\n## コンポーネントの `Scope<_>` インターフェース\n\n`Scope` は、メッセージを介してコールバックを作成し、自身を更新するメカニズムです。コンポーネントに渡されるコンテキストオブジェクトで `link()` を呼び出すことで、その参照を取得します。\n\n### `send_message`\n\nこの関数は、コンポーネントにメッセージを送信できます。メッセージは `update` メソッドによって処理され、コンポーネントが再レンダリングするかどうかを決定します。\n\n### `send_message_batch`\n\nこの関数は、コンポーネントに複数のメッセージを同時に送信できます。これは `send_message` に似ていますが、任意のメッセージが `update` メソッドで `true` を返す場合、バッチ内のすべてのメッセージの処理が完了した後にコンポーネントが再レンダリングされます。\n\n指定された引数ベクターが空の場合、この関数は何も実行しません。\n\n### `callback`\n\nコールバックを作成し、実行時にコンポーネントにメッセージを送信します。内部的には、提供されたクロージャが返すメッセージを使用して `send_message` を呼び出します。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // テキストを受け取り、それを `Msg::Text` メッセージバリアントとしてコンポーネントに送信するコールバックを作成します。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上の行は冗長であり、より明確にするために次のように簡略化できます：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // `Msg::Text(\"Hello World!\")` をコンポーネントに送信します。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // ここに HTML を配置\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nバッチメッセージを送信するコールバックを作成します。このメソッドに渡されるクロージャはメッセージを返す必要はありません。代わりに、クロージャは `Vec<Msg>` または `Option<Msg>` を返すことができます。ここで、`Msg` はコンポーネントのメッセージタイプです。\n\n`Vec<Msg>` はバッチメッセージとして扱われ、内部的に `send_message_batch` を使用します。\n\n`Option<Msg>` は値が `Some` の場合に `send_message` を呼び出します。値が `None` の場合は何も実行しません。これは、更新が不要な場合に使用できます。\n\nこれは、これらの型に対してのみ実装された `SendAsMessage` トレイトを使用して実現されています。独自の型に対して `SendAsMessage` を実装することで、`batch_callback` でそれらを使用できるようになります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/agents.mdx",
    "content": "---\ntitle: 'エージェント (Agents)'\ndescription: 'Yew のエージェントシステム'\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nエージェント (Agents) は、タスクを Web Workers にオフロードする方法です。\n\nエージェントが並行して動作できるようにするために、Yew は [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) を使用します。\n\n## ライフサイクル\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## エージェントの種類\n\n### 範囲\n\n- 公開 - 任意の時点で、公開エージェントのインスタンスは最大で1つだけです。ブリッジはWeb Worker内でエージェントを生成するか、既に生成されたエージェントに接続します。ブリッジがこのエージェントに接続されていない場合、エージェントは消滅します。\n\n- 私有 - 新しいブリッジごとにWeb Worker内で新しいエージェントを生成します。これは、ブラウザと通信する共有だが独立した動作をコンポーネントから移動するのに適しています。接続されたブリッジが破棄されると、エージェントは消滅します。\n\n- グローバル \\(WIP\\)\n\n## エージェントとコンポーネント間の通信\n\n### 通信ブリッジ (Bridges)\n\n通信ブリッジ（ブリッジ）は、コンポーネントとエージェント間の通信チャネルです。これにより、コンポーネントはエージェントにメッセージを送信し、エージェントからのメッセージを受信できます。\n\n`use_bridge` フックは、関数コンポーネント内でブリッジを作成する機能も提供します。\n\n### ディスパッチャー (Dispatchers)\n\nディスパッチャー（ディスパッチャー）は、コンポーネントとエージェント間の一方向通信を可能にし、コンポーネントがこの方法でエージェントにメッセージを送信します。\n\n## オーバーヘッド\n\nエージェントはWeb Workers（つまり、私有および公開）を使用します。メッセージの送受信時にシリアル化オーバーヘッドが発生します。エージェントは [bincode](https://github.com/bincode-org/bincode) を使用して他のスレッドと通信するため、コストは関数を呼び出すだけの場合よりもはるかに高くなります。\n\n## さらなる読み物\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) の例は、コンポーネントがエージェントにメッセージを送信し、エージェントからのメッセージを受信する方法を示しています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'classes! マクロを使用して CSS クラスを処理する'\ndescription: '便利なマクロを使用して CSS クラスを処理する'\ncomment: 'ファイルを短くシンプルに保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためであり、正確な API ドキュメントを提供するためではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew はネイティブの CSS-in-Rust ソリューションを提供していませんが、HTML の `class` 属性とプログラム的に対話する方法を提供することでスタイルを支援します。\n\n## `classes!` マクロ\n\n`classes!` マクロと関連する `Classes` 構造体は、HTML クラスの使用を簡素化します：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。\n\n## インラインスタイル\n\n現在、Yew は `style` 属性を使用して指定されたインラインスタイルを処理するための特別な支援ツールを提供していませんが、他の HTML 属性と同様に処理することができます：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'html! マクロを使用してHTMLを処理する'\ndescription: 'これはHTMLですが、完全にそうではありません！'\ncomment: 'ファイルを短く簡潔に保つようにしてください。これは、読者がYewのコンポーネントをより簡単に理解できるようにするためであり、正確なAPIドキュメントを提供するためではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロを使用して、HTML に似た式を記述できます。Yew はバックグラウンドでそれを DOM を表現する Rust コードに変換します。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nフォーマットされた式と同様に、波括弧を使用して周囲のコンテキストの値を HTML に埋め込むことができます：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n`html!` を使用する際の重要なルールの 1 つは、1 つのラッピングノードしか返せないということです。複数の要素のリストをレンダリングするために、`html!` は空のタグ（フラグメント）の使用を許可しています。空のタグは名前のないタグで、それ自体は HTML 要素を生成しません。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// エラー：ルート HTML 要素は1つだけ許可されています\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修正：HTML 空のタグを使用してラップする\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n詳細については、[HTML の詳細](concepts/html/introduction.mdx)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JavaScript と Rust'\ndescription: 'Rust で JavaScript を使用する'\ncomment: 'ファイルを簡潔に保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためのものであり、正確な API ドキュメントを提供するためのものではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew は、再利用可能な UI 部分に必要なすべてのコンテンツを1か所に集める一方で、必要に応じて基盤技術へのアクセスも維持します。\n\n今日現在、WebAssembly は DOM との相互作用を完全にはサポートしていません。これは、Yew でも時々 JavaScript の呼び出しに依存することを意味します。次に、関係するライブラリの概要を示します。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しの橋を架けるライブラリとツールです。\n\n彼らの[ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/)と私たちの[クイックガイド](./wasm-bindgen.mdx)を強くお勧めします。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) は Web API のバインディングを提供し、Rust で処理され安全な方法で JavaScript コードを書くことを可能にします。\n\n例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n繰り返しになりますが、彼らの[ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/)と私たちの[クイックガイド](./web-sys.mdx)を強くお勧めします。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しブリッジを作成するためのライブラリおよびツールです。これは [Rust と WebAssembly ワーキンググループ](https://rustwasm.github.io/) によって Rust で構築されました。\n\nYew は `wasm-bindgen` を使用して、いくつかのクレートを介してブラウザと対話します：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nこのセクションでは、これらのクレートをより抽象的なレベルから探求し、Yew での `wasm-bindgen` API の理解と使用を容易にします。`wasm-bindgen` および関連するクレートに関する詳細なガイドについては、[`wasm-bindgen` ガイド](https://wasm-bindgen.github.io/wasm-bindgen/) を参照してください。\n\n上記のクレートのドキュメントについては、[`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) を参照してください。\n\n:::tip\n`wasm-bindgen` doc.rs 検索を使用して、`wasm-bindgen` を使用してインポートされたブラウザ API および JavaScript タイプを見つけます。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nこのクレートは、上記の他のクレートに多くの構成要素を提供します。このセクションでは、`wasm-bindgen` クレートの主要な領域の 2 つ、つまりマクロと、何度も目にするタイプ/トレイトのいくつかについてのみ説明します。\n\n### `#[wasm_bindgen]` マクロ\n\n`#[wasm_bindgen]` マクロは Rust と JavaScript の間のインターフェースを提供し、両者の間で変換を行うシステムを提供します。このマクロの使用はより高度であり、外部の JavaScript ライブラリを使用する場合を除いて使用しないでください。`js-sys` および `web-sys` クレートは、組み込みの JavaScript タイプおよびブラウザ API に対して `wasm-bindgen` 定義を提供します。\n\n`#[wasm-bindgen]` マクロを使用して、特定のバージョンの [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 関数をインポートする簡単な例を見てみましょう。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// まず、`web_sys` を使用せずに `console.log` を手動でバインドしてみましょう。\n// ここでは、手動で `#[wasm_bindgen]` アノテーションを書きます。プログラムの正確性はこれらのアノテーションの正確性に依存します！\n#[wasm_bindgen]\nextern \"C\" {\n    // ここで `js_namespace` を使用して `console.log(..)` をバインドします。`log(..)` だけではありません。\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` は多態的なので、複数のシグネチャを使用してバインドできます。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 複数の引数も可能です！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// インポートされた関数を使用します！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_この例は、[1.2 `wasm-bindgen` ガイドの console.log を使用する](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) に基づいています。_\n\n### 継承のシミュレーション\n\nJavaScript クラス間の継承は、JavaScript 言語のコア機能であり、DOM（ドキュメントオブジェクトモデル）はそれを中心に設計されています。`wasm-bindgen` を使用して型をインポートする際にも、それらの継承関係を記述する属性を追加できます。\n\nRust では、この継承関係は [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) と [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) トレイトを使用して表現されます。ここで例を挙げると役立つかもしれません。例えば、`A`、`B`、`C` という 3 つの型があり、`C` が `B` を拡張し、`B` が `A` を拡張しているとします。\n\nこれらの型をインポートする際、`#[wasm-bindgen]` マクロは次のように `Deref` と `AsRef` トレイトを実装します：\n\n- `C` は `B` に `Deref` できます\n- `B` は `A` に `Deref` できます\n- `C` は `B` に `AsRef` できます\n- `C` と `B` はどちらも `A` に `AsRef` できます\n\nこれらの実装により、`C` のインスタンスで `A` のメソッドを呼び出したり、`C` を `&B` または `&A` として使用したりできます。\n\n注意すべき点は、`#[wasm-bindgen]` を使用してインポートされたすべての型には同じルート型があり、それを上記の例の `A` と見なすことができるということです。この型は [`JsValue`](#jsvalue) であり、以下にそのセクションがあります。\n\n_[`wasm-bindgen` ガイドの extends セクション](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\nこれは JavaScript が所有するオブジェクトの表現であり、`wasm-bindgen` のルートキャプチャ型です。`wasm-bindgen` からの任意の型は `JsValue` です。これは、JavaScript には強い型システムがないため、変数 `x` を受け取る任意の関数がその型を定義しないため、`x` は有効な JavaScript 値である可能性があるためです。したがって `JsValue` です。`JsValue` を受け取るインポート関数や型を使用している場合、技術的には任意のインポート値が有効です。\n\n`JsValue` は関数で受け取ることができますが、その関数は特定の型のみを受け取る可能性があり、それがパニックを引き起こす可能性があります。したがって、元の `wasm-bindgen` API を使用する場合は、インポートされた JavaScript のドキュメントを確認して、その値が特定の型でない場合に例外（パニック）を引き起こすかどうかを確認してください。\n\n_[`JsValue` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)_\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust には強い型システムがありますが、JavaScript にはありません😞。Rust がこれらの強い型を維持しながらも便利であるために、WebAssembly ワーキンググループは非常に巧妙な機能 `JsCast` を提案しました。これは、ある JavaScript \"型\" から別の \"型\" への変換を支援するものです。これは曖昧に聞こえますが、ある型が別の型であることがわかっている場合、`JsCast` の関数を使用してある型から別の型にジャンプできます。`web-sys`、`wasm_bindgen`、`js-sys` を使用する際にこの機能を理解しておくと便利です。これらのクレートから多くの型が `JsCast` を実装していることに気付くでしょう。\n\n`JsCast` はチェック付きとチェックなしの変換メソッドを提供します。したがって、実行時にオブジェクトがどの型であるかわからない場合は、変換を試みることができ、失敗する可能性のある型として [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) や [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) を返します。\n\n一般的な例は [`web-sys`](./web-sys.mdx) で、イベントのターゲットを取得しようとする場合です。ターゲット要素が何であるかを知っているかもしれませんが、[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API は常に [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を返します。\nその要素型に変換する必要があり、そのメソッドを呼び出すことができます。\n\n```rust\n// このトレイトを最初にインポートする必要があります\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // もしかしたらターゲットは選択要素かもしれませんか？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 別のことをする\n        return;\n    }\n\n    // それが選択要素でないことが確実であれば、入力要素であることが確実です！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) メソッドはチェック付きの変換であり、`Option<&T>` を返します。これは、変換が失敗した場合に元の型を再度使用できることを意味し、`None` を返します。 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) メソッドは `self` を消費し、Rust の `into` メソッドの規約に従い、`Result<T, Self>` 型を返します。変換が失敗した場合、元の `Self` 値は `Err` に返されます。再試行するか、元の型で他の操作を行うことができます。\n\n_[`JsCast` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 型は、Rust のクロージャを JavaScript に渡す方法を提供します。健全性の理由から、JavaScript に渡されるクロージャは `'static` ライフタイムを持つ必要があります。\n\nこの型は「ハンドル」であり、破棄されると、それが参照する JS クロージャを無効にします。`Closure` が破棄された後、JS 内のクロージャの使用はすべて例外を引き起こします。\n\n`Closure` は、[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 型を受け取る `js-sys` または `web-sys` API を使用する際に一般的に使用されます。Yew で `Closure` を使用する例は、[Events](../html/events.mdx) ページの[Using `Closure` セクション](../html/events.mdx#using-closure-verbose) にあります。\n\n_[`Closure` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` クレートは、JavaScript の標準組み込みオブジェクトのバインディング/インポートを提供します。これには、それらのメソッドやプロパティが含まれます。\n\nこれは Web API を含みません。Web API は [`web-sys`](./web-sys.mdx) の役割です！\n\n_[`js-sys` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` クレートは、JavaScript の Promise 型を Rust の [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) として扱うためのブリッジを提供し、Rust の Future を JavaScript の Promise に変換するユーティリティを含みます。Rust（wasm）で非同期または他のブロッキング作業を処理する際に役立ち、JavaScript のイベントや JavaScript I/O プリミティブと対話する能力を提供します。\n\n現在、このクレートには3つの主要なインターフェースがあります：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) を使用して構築された型で、`Future<Output=Result<JsValue, JsValue>>` として使用できます。`Promise` が解決されると、この `Future` は `Ok` に解決され、`Promise` が拒否されると `Err` に解決され、それぞれ `Promise` の解決または拒否の値を含みます。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Rust の `Future<Output=Result<JsValue, JsValue>>` を JavaScript の `Promise` に変換します。Future の結果は、JavaScript 内の解決または拒否された `Promise` に変換されます。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   現在のスレッドで `Future<Output = ()>` を生成します。これは、Rust 内で Future を実行する最良の方法であり、JavaScript に送信するのではなく、Rust 内で実行します。\n\n_[`wasm-bindgen-futures` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` は、非同期 API を使用するライブラリを使用する際に、Yew で `wasm-bindgen-futures` クレートの最も一般的に使用される部分です。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // \"Hello, world!\" を出力します\n    console::log_1(&string.into());\n});\n```\n\nYew はいくつかの API に futures のサポートを追加しており、特に `async` ブロックを受け入れる `callback_future` を作成できることが注目されます。これは内部的に `spawn_local` を使用しています。\n\n_[`spawn_local` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys クレートは Web API のバインディングを提供します。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` クレート](https://crates.io/crates/web-sys) は Web API のバインディングを提供します。これはブラウザの WebIDL から生成されるため、名前が長くなったり、型が曖昧になったりすることがあります。\n\n## `web-sys` の特性 (features)\n\n`web-sys` クレートで全ての特性を有効にすると、Wasm アプリケーションに多くの冗長性が追加される可能性があります。この問題を解決するために、ほとんどの型は特性を有効にすることで制御され、アプリケーションに必要な型だけを含めることができます。Yew は `web-sys` のいくつかの特性を有効にし、その公開 API でいくつかの型を公開しています。通常、`web-sys` を依存関係として追加する必要があります。\n\n## `web-sys` の継承\n\n[継承のシミュレーション](./wasm-bindgen.mdx#simulating-inheritance)のセクションでは、Rust が通常 JavaScript の継承をシミュレートする方法を提供していることがわかります。これは `web-sys` で非常に重要です。ある型にどのようなメソッドがあるかを理解するためには、その継承を理解する必要があります。\n\nこのセクションでは、特定の要素を見て、Rust で [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) を呼び出して、その値が [`JsValue`](./wasm-bindgen.mdx#jsvalue) になるまでの継承をリストします。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement は HTML の <textarea> です。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意: ここで web-sys タイプから js-sys クレート内の組み込み JavaScript タイプに移行しました。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意: ここで js-sys タイプから wasm-bindgen クレートのルート JsValue に移行しました。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // このように deref を使用することで、継承ツリーを手動でたどる必要があります。\n    // しかし、HtmlTextAreaElement タイプで JsValue メソッドを呼び出すことができます。\n    assert!(!text_area.is_string());\n\n    // この空の関数は、HtmlTextAreaElement を &EventTarget として渡すことができることを示すためのものです。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // コンパイラはここでタイプを一致させるために deref チェーンを下にたどります。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 実装により、HtmlTextAreaElement を &EventTarget として扱うことができます。\n    let event_target: &EventTarget = text_area.as_ref();\n}\n```\n\n[`wasm-bindgen` ガイドの `web-sys` 継承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)\n\n## `NodeRef` の `Node`\n\nYew は [`NodeRef`](concepts/function-components/node-refs.mdx) を使用して、[`html!`](concepts/html/introduction.mdx) マクロによって作成された `Node` の参照を保持する方法を提供します。`NodeRef` の `Node` は [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html) を指します。`NodeRef::get` メソッドは `Option<Node>` 値を返しますが、Yew ではほとんどの場合、この値を特定の要素に変換して、その特定のメソッドを使用することを望みます。存在する場合、[`JsCast`](./wasm-bindgen.mdx#JsCast) を使用して `Node` 値を変換できますが、Yew はこの変換を実行するための `NodeRef::cast` メソッドを提供しているため、`JsCast` 特性のために `wasm-bindgen` 依存関係を含める必要はありません。\n\n以下の2つのコードブロックは本質的に同じです。最初のものは `NodeRef::cast` を使用し、2 番目のものは `NodeRef::get` が返す `web_sys::Node` 上で [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) を使用しています。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // HtmlInputElement をここで処理します\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // HtmlInputElement をここで処理します\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Rust にリファクタリングされた JavaScript の例\n\nこのセクションでは、Web API と対話する JavaScript コードの例を Rust の `web-sys` にリファクタリングする方法を示します。\n\n### JavaScript の例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e はマウスイベントオブジェクトです\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 要素内の x 位置。\n    var y = e.clientY - rect.top // 要素内の y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` を使用して書き直した例\n\n`web-sys` のみを使用して、上記の JavaScript の例は次のように実装できます：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 使用したいすべての web-sys 機能を有効にする必要があります！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 現在、イベントが発生したときにクロージャがメモリに残るように、`mousemove` クロージャを保存する必要があります。\n```\n\nこのバージョンはより冗長ですが、その一部は失敗した型が私たちにいくつかの関数呼び出しに保持しなければならない不変条件を思い出させるためです。これらの不変条件が守られないと、Rust ではパニックが発生します。もう一つの冗長な部分は、特定のメソッドを呼び出すために異なる型を特定の型に変換するための `JsCast` の呼び出しです。\n\n### Yew で書き直した例\n\nYew では、主に [`Callback`](concepts/function-components/callbacks.mdx) を作成して [`html!`](concepts/html/introduction.mdx) マクロで使用するため、例はこの方法を使用します。上記の方法を完全にコピーするのではなく、この方法を使用します：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# `get_bounding_client_rect` メソッドを使用するには、`DomRect` 特性を有効にする必要があります。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 追加の依存ライブラリ\n\n`web-sys` は Web API の生のバインディングであるため、Rust で使用する際にはいくつかの困難が伴います。これは、`web-sys` が Rust や強い型システムのために設計されていないためです。そこで、コミュニティのクレートが `web-sys` に対する抽象化を提供し、Rust の慣習により適した API を提供しています。\n\n_[追加の依存ライブラリ一覧](/community/external-libs)_\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/contexts.mdx",
    "content": "---\ntitle: 'コンテキスト (Contexts)'\nsidebar_label: コンテキスト\ndescription: 'コンテキストを使用して深くネストされたデータを渡す'\n---\n\n通常、データは props を介して親コンポーネントから子コンポーネントに渡されます。\nしかし、多くの中間コンポーネントを介してデータを渡す必要がある場合や、アプリケーション内の多くのコンポーネントが同じ情報を必要とする場合、props を介してデータを渡すことは冗長で煩わしいものになります。\nコンテキストはこの問題を解決し、親コンポーネントがデータをその下のツリー内の任意のコンポーネントに渡すことを可能にし、props を介してデータを渡す必要がなくなります。\n\n## Props を使用する際の問題：\"Prop Drilling\"\n\n[props](./function-components/properties.mdx) を介してデータを親コンポーネントから直接子コンポーネントに渡すことは良い方法です。\nしかし、深くネストされたコンポーネントツリーを介してデータを渡す必要がある場合や、複数のコンポーネントが同じデータを共有する必要がある場合、props を渡すことは煩雑になります。\n一般的なデータ共有の解決策は、データを共通の祖先に持ち上げ、子コンポーネントがそれを props として受け取るようにすることです。\nしかし、これにより props が複数のコンポーネントを介して渡される必要がある場合があります。\nこの状況は \"Prop Drilling\" と呼ばれます。\n\n以下の例を考えてみましょう。これは props を介してテーマを渡しています：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// アプリのルート\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n私たちはテーマ設定を `Navbar` に渡して、それが `Title` と `NavButton` に到達するようにしています。\nもし `Title` と `NavButton` のようなテーマにアクセスする必要があるコンポーネントが、prop を介さずに直接テーマにアクセスできるとしたら、もっと良いでしょう。\nコンテキストはこの問題を解決し、親コンポーネントがデータ（この場合はテーマ）をその子コンポーネントに渡すことを可能にします。\n\n## コンテキストの使用\n\n### ステップ 1：コンテキストの提供\n\nコンテキストを消費するには、コンテキストプロバイダーが必要です。`ContextProvider<T>` は、`T` がコンテキスト構造体として使用されるプロバイダーです。\n`T` は `Clone` と `PartialEq` を実装する必要があります。`ContextProvider` は、その子コンポーネントがコンテキストを持つコンポーネントです。\nコンテキストが変更されると、子コンポーネントは再レンダリングされます。データを渡すための構造体が定義されます。`ContextProvider` は次のように使用できます：\n\n```rust\nuse yew::prelude::*;\n/// アプリのテーマ\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// メインコンポーネント\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` は `Rc<UseStateHandle<Theme>>` 型であり、`Theme` が必要です\n        // したがって、デリファレンスします。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // ここにあるすべての子コンポーネントとその子コンポーネントは、このコンテキストにアクセスします。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// ツールバー\n/// このコンポーネントはコンテキストにアクセスできます。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// `Toolbar` 内に配置されたボタン\n/// このコンポーネントは、コンポーネントツリー内の `ThemeContextProvider` の子コンポーネントであるため、\n/// コンテキストにアクセスできます。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### ステップ 2：コンテキストの使用\n\n#### 関数コンポーネント\n\n`use_context` フックは、関数コンポーネント内でコンテキストを使用するために使用されます。\n詳細については、[use_context ドキュメント](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) を参照してください。\n\n#### 構造体コンポーネント\n\n構造体コンポーネント内でコンテキストを使用するには、2つの方法があります：\n\n- [高階コンポーネント](../advanced-topics/struct-components/hoc)：高階関数コンポーネントがコンテキストを使用し、必要なデータを構造体コンポーネントに渡します。\n- 構造体コンポーネント内で直接コンテキストを使用します。詳細については、[構造体コンポーネントのコンシューマーとしての例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs) を参照してください。\n\n## 使用シナリオ\n\n通常、ツリーの異なる部分のリモートコンポーネントでデータを使用する必要がある場合、コンテキストが役立ちます。\n以下はいくつかの例です：\n\n- **テーマ**：アプリケーションのトップにコンテキストを配置し、アプリケーションのテーマを保持し、視覚的な外観を調整するために使用できます（上記の例を参照）。\n- **現在のユーザーアカウント**：多くの場合、コンポーネントは現在ログインしているユーザーを知る必要があります。コンテキストを使用して、現在のユーザーオブジェクトをコンポーネントに提供できます。\n\n### コンテキストを使用する前の考慮事項\n\nコンテキストは非常に使いやすいですが、それが誤用/過度に使用される可能性もあります。\n複数のレベル深いコンポーネントに props を共有するためにコンテキストを使用できるからといって、必ずしもそうすべきではありません。\n\n例えば、コンポーネントを抽出して、そのコンポーネントを別のコンポーネントの子コンポーネントとして渡すことができます。\n例えば、`Layout` コンポーネントが `articles` を prop として受け取り、それを `ArticleList` コンポーネントに渡す場合、\n`Layout` コンポーネントをリファクタリングして、子コンポーネントを props として受け取り、`<Layout> <ArticleList {articles} /> </Layout>` と表示するようにするべきです。\n\n## 子コンポーネントのコンテキスト値を変更する\n\nRust の所有権ルールにより、コンテキストには子コンポーネントが呼び出せる `&mut self` メソッドを持つことができません。\nコンテキストの値を変更するには、リデューサーと組み合わせて使用する必要があります。これは、[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) フックを使用して行うことができます。\n\n[コンテキストの例](https://github.com/yewstack/yew/tree/master/examples/contexts) は、可変コンテキストの使用を示しています。\n\n## さらなる読み物\n\n- [コンテキストの例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'コールバック (Callbacks)'\n---\n\nコールバック関数は、コンポーネントツリー内で情報を上向きに伝達したり、イベント処理中に他のコンポーネント（例えばエージェントやDOM）と通信したりするために使用されます。内部的には、コールバック関数の型は単なる `Fn` であり、安価にクローンできるように `Rc` に包まれています。\n\nコールバック関数を手動で呼び出したい場合は、`emit` 関数を使用できます。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // コールバック関数を呼び出す\n// web_sys::console::log_1(&result.into()); // コメントを解除すると、「Bye Bob」 が出力されます\n```\n\n## コールバック関数をプロパティとして渡す\n\nyew で一般的なパターンは、コールバック関数を作成し、それをプロパティとして子コンポーネントに渡すことです。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 次にプロパティ (Props) を提供します\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // コメントを解除すると、ここにテキストが出力されます\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM イベントとコールバック関数\n\nコールバック関数は、DOM イベントに接続するためにも使用されます。\n\n例えば、ここではユーザーがボタンをクリックしたときに呼び出されるコールバック関数を定義します：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // コメントを解除すると、ここにテキストが出力されます\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子要素 (Children)'\n---\n\n`Children` は特別なプロパティタイプで、HTMLの子要素のようにネストされた `Html` を受け取ることができます。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` キーは重要です！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // この方法で子要素を転送できます\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'コンポーネント間の通信'\n---\n\n## 親コンポーネントから子コンポーネントへのメッセージ送信\n\nデータを [props](./properties) として渡すと、再レンダリングが発生し、これが子コンポーネントにメッセージを渡す方法です。\n\n## 子コンポーネントから親コンポーネントへのメッセージ送信\n\nprops を介してコールバックを渡し、子コンポーネントはイベントでそれを呼び出すことができます。[例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'ジェネリックコンポーネント'\ndescription: '関数コンポーネントの #[component] 属性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 属性は、ジェネリックコンポーネントを作成するためのジェネリック関数にも適用されます。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// その後、このように使用できます\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// または\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'カスタムフック'\n---\n\n## カスタムフックの定義\n\nコンポーネントのステートフルなロジックは、カスタムフックを作成することで再利用可能な関数として抽出できます。\n\n例えば、`window` オブジェクト上のイベントをリッスンするイベントリスナーを作成したいとします。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nこのコードには問題があります。ロジックは他のコンポーネントで再利用できません。異なるイベントをリッスンする別のコンポーネントを作成する場合、コードをコピーするのではなく、ロジックをカスタムフックに移すことができます。\n\nまず、`use_event` という新しい関数を作成します。`use_` プレフィックスは関数がフックであることを示します。この関数はイベントターゲット、イベントタイプ、およびコールバックを受け取ります。すべてのフックはその関数定義に `#[hook]` とマークする必要があります。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nこのシンプルなフックは、組み込みのフックを組み合わせることで作成できます。この例では、`use_effect_with` フックを使用します。これにより、フックのパラメータが変更されたときにイベントリスナーを再作成できます。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nこの方法はほとんどすべてのケースで有効ですが、私たちがすでに使用しているような基本的なフックを作成するためには使用できません。\n\n[docs.rs](https://docs.rs/yew) 上のドキュメントや `hooks` ディレクトリを参照して、事前定義されたフックの実装を確認してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks は、状態を保存し、副作用を実行することができる関数の一種です。\n\nYew はいくつかの事前定義された hooks を提供しています。また、自分で hooks を作成することもできますし、多くの[コミュニティ製の hooks](/community/awesome#hooks) を見つけることもできます。\n\n## Hooks のルール\n\n1. 各 Hook 関数の名前は `use_` で始める必要があります\n2. Hooks は次の場所でのみ使用できます：\n    - 関数/ Hook のトップレベル\n    - 関数/ Hook 内のブロック、ただし分岐していない場合\n    - 関数/ Hook 内トップレベルの `if` 式の条件\n    - 関数/ Hook 内トップレベルの `match` 式のセレクター\n3. 各レンダリング時に、Hooks は同じ順序で呼び出される必要があります。[Suspense](../../suspense.mdx) を使用する場合のみ、早期リターンが許可されます\n\nこれらのルールは、コンパイル時または実行時のエラーによって強制されます。\n\n### 事前定義された Hooks\n\nYew は次の事前定義された Hooks を提供しています：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nこれらの hooks のドキュメントは [Yew API ドキュメント](https://yew-rs-api.web.app/next/yew/functional/)で見つけることができます。\n\n### カスタム Hooks\n\n場合によっては、独自の Hooks を定義して、コンポーネント内の状態を持つ可能性のあるロジックを再利用可能な関数にカプセル化することが望ましいことがあります。\n\n## さらなる読み物\n\n- React ドキュメントには [React hooks](https://reactjs.org/docs/hooks-intro.html) に関するセクションがあります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '関数コンポーネント'\nslug: /concepts/function-components\n---\n\n以前のスローガンをもう一度見てみましょう：\n\n> Yew の核心思想は、再利用可能な UI 部分に必要なすべての内容を 1 つの場所 - Rust ファイルに集中させることです。\n\nこの声明を完成させるために、アプリケーションのロジックとレンダリングの動作を定義する概念を導入します：\"コンポーネント\"。\n\n## コンポーネントとは？\n\nコンポーネントは Yew の構成要素です。\n\nそれらは次のことを行うべきです：\n\n- [Props](./properties.mdx) の形式でパラメータを受け取る\n- 独自の状態を持つことができる\n- ユーザーに見える HTML フラグメント（DOM）を計算する\n\n## Yew コンポーネントの 2 つのフレーバー\n\n現在、関数コンポーネントについて読んでいます - これは Yew を使い始めるときや、シンプルなレンダリングロジックを書くときにコンポーネントを書くための推奨方法です。\n\nもう一つの、より高度ですがアクセスしにくいコンポーネントの書き方があります - [構造コンポーネント](advanced-topics/struct-components/introduction.mdx)。それらは非常に詳細な制御を可能にしますが、ほとんどの場合、そこまで詳細な制御は必要ありません。\n\n## 関数コンポーネントの作成\n\n関数コンポーネントを作成するには、関数に `#[component]` 属性を追加します。慣例として、関数の名前は PascalCase を使用し、`html!` マクロ内の通常の html 要素と対比させます。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// そして他の場所で、`html!` 内でコンポーネントを使用できます\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## コンポーネント内部で何が起こっているのか\n\nレンダリング時に、Yew はこれらのコンポーネントの仮想ツリーを構築します。各（関数）コンポーネントの view 関数を呼び出して、DOM の仮想バージョン（VDOM）を計算します。ライブラリのユーザーとして、これを `Html` 型として扱います。上記の例では、次のようになります：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n更新が必要な場合、Yew は再び view 関数を呼び出し、新しい仮想 DOM を以前のバージョンと調整し、新しい/変更された/必要な部分のみを実際の DOM に伝播します。これが **レンダリング** と呼ばれるものです。\n\n:::note\n\n実際には、`Html` は `VNode` の別名に過ぎません - 仮想ノードです。\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'ノード参照'\ndescription: 'DOM 外部アクセス'\n---\n\n`ref` 属性を使用して、`NodeRef` を HTML 要素にアタッチできます。コールバック内で、`ref` がアタッチされた DOM `Element` を取得できます。これを使用して、`view` ライフサイクルメソッドの外部で DOM を変更したり、`<input>` の値を取得したり、JavaScript API を介して直接 DOM と対話したりできます。\n\nこれは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。\n\n:::caution\nYew がレンダリングした DOM ツリーを手動で変更しないでください。確信が持てない場合は、`NodeRef` を読み取り専用アクセスとして扱ってください。\n:::\n\n## さらに読む\n\n- [use_node_ref フック](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` の例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Properties)'\ndescription: '親子コンポーネントの通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nプロパティ (Properties) は通常 \"Props\" と略されます。\n\n:::\n\nプロパティ (Properties) はコンポーネントのパラメータであり、Yew はこれらのパラメータを監視できます。\n\nコンポーネントのプロパティで型を使用する前に、その型は `Properties` トレイトを実装している必要があります。\n\n## リアクティブ性\n\n再レンダリング時に、Yew は仮想DOMを調整する際にプロパティが変更されたかどうかを確認し、ネストされたコンポーネントを再レンダリングする必要があるかどうかを判断します。これにより、Yew は非常にリアクティブなフレームワークと見なされます。親コンポーネントからの変更は常に下位に伝播し、ビューはプロパティ/状態からのデータと常に同期します。\n\n:::tip\n\nまだ [チュートリアル](../../tutorial) を完了していない場合は、このリアクティブ性を自分でテストしてみてください！\n\n:::\n\n## 派生マクロ\n\nYew は、構造体に `Properties` トレイトを簡単に実装できる派生マクロを提供します。\n\n`Properties` を派生する型は、Yew がデータ比較を行えるように `PartialEq` も実装している必要があります。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 関数コンポーネントでの使用\n\n属性 `#[component]` は、関数の引数で Props を選択的に受け取ることを可能にします。それらを提供するには、`html!` マクロ内の属性を通じて割り当てることができます。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// そしてプロパティを提供します\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 提供するプロパティはありません\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生マクロフィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。\n\n以下の属性を使用すると、親コンポーネントがそれらを設定しなかった場合にデフォルト値を提供することができます。\n\n:::tip\n属性は Rustdoc によって生成されたドキュメントには表示されません。属性のドキュメント文字列には、その属性がオプションであるかどうか、および特定のデフォルト値があるかどうかを記載する必要があります。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n`Default` トレイトを使用して、フィールド型のデフォルト値でプロパティ値を初期化します。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。\n\n例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。プロパティが構築されるときに、式が評価され、明示的な値が与えられていない場合に適用されます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n属性値を初期化するために `function` を呼び出します。`function` は `FnMut() -> T` シグネチャを持つ必要があり、ここで `T` はフィールドの型です。このプロパティに明示的な値が与えられていない場合、その関数が呼び出されます。\nこの関数はプロパティが構築されるときに呼び出されます。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたスマートポインタとして渡されます。これにより、コンポーネントツリー内のプロパティに対して共有ポインタが1つだけ渡されるため、プロパティ全体をクローンする高コストを節約できます。\n\n:::tip\n`AttrValue` はプロパティ値に使用するカスタムタイプであり、これにより String やその他のクローンコストが高いタイプとして定義する必要がなくなります。\n:::\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、プロパティや基本式 (`Foo { ..base }`) を使用することはできません。タイプパスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 名前属性を指定する必要はありません\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自動生成プロパティ (yew-autoprops)\n\n開発プロセスを簡素化するために、`#[autoprops]` マクロ（`yew-autoprops` パッケージから）を使用して `Properties` 構造体を自動生成することもできます。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] マクロは #[component] の前に配置する必要があります。順序が重要です。\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 構造体 \"GreetingsProps\" は自動的に生成されます。\n//\n// `is_loading` は値としてコンポーネントに渡され、`message` と `name` は定義に先行する `&` があるため参照として渡されます。\n```\n\n## 評価順序\n\n属性は指定された順序で評価されます。以下の例を参照してください：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## アンチパターン\n\nほとんどのRust型はプロパティとして渡すことができますが、避けるべきアンチパターンがいくつかあります。これらには以下が含まれますが、これに限定されません：\n\n1. `String` 型を `AttrValue` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `String` のクローンは高コストです。プロパティ値がフックやコールバックと一緒に使用される場合、通常クローンが必要です。`AttrValue` は参照カウントされた文字列 (`Rc<str>`) または `&'static str` であり、非常に安価にクローンできます。<br />\n   **注意**：`AttrValue` は内部的には [implicit-clone](https://crates.io/crates/implicit-clone) からの `IString` です。詳細はそのパッケージを参照してください。\n2. 内部可変性を使用する。 <br />\n   **なぜ悪いのか？** 内部可変性（例えば `RefCell`、`Mutex` など）は _通常_ 避けるべきです。これにより再レンダリングの問題が発生する可能性があり（Yewは状態が変更されたことを認識しません）、手動で再レンダリングを強制する必要があるかもしれません。すべてのものと同様に、適切な使用場所があります。慎重に使用してください。\n3. `Vec<T>` 型を `IArray<T>` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `Vec<T>` も `String` と同様にクローンのコストが高いです。`IArray<T>` は参照カウントされたスライス (`Rc<[T]>`) または `&'static [T]` であり、非常に安価にクローンできます。<br />\n   **注意**：`IArray` は [implicit-clone](https://crates.io/crates/implicit-clone) からインポートできます。詳細はそのパッケージを参照してください。\n4. 新しい発見があるかもしれません。早く知っておきたかったエッジケースに遭遇しましたか？問題を作成するか、このドキュメントに修正のPRを提供してください。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) は実験的なパッケージで、関数の引数に基づいて動的にProps構造体を作成することを可能にします。プロパティ構造体が再利用されない場合、これは有用かもしれません。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '純粋コンポーネント'\n---\n\nすべての関数コンポーネントは、プロパティオブジェクトを受け取り、`Html` オブジェクトを返す[純粋](https://ja.wikipedia.org/wiki/%E7%B4%94%E9%96%A2%E6%95%B0)関数です。純粋関数とは、同じ入力に対して常に同じ出力を返す関数のことです。\n\nこの例は純粋コンポーネントです。与えられたプロパティ `is_loading` に対して、常に同じ `Html` を返し、副作用はありません。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n内部の純粋コンポーネントがフックや他のコンポーネントメカニズムを使用しない場合、それを `Html` を返す通常の関数として記述することができ、Yew がコンポーネントのライフサイクルに関連するオーバーヘッドを回避することができます。[式構文](concepts/html/literals-and-expressions.mdx#expressions) を使用して `html!` 内でそれらをレンダリングします。\n:::\n\n## 非純粋コンポーネント\n\nコンポーネントがグローバル変数を使用しない場合、それが「純粋」でない可能性があるかどうか疑問に思うかもしれません。なぜなら、それは毎回レンダリングされる固定関数として呼び出されるだけだからです。\nこれが次のトピック - [フック](./hooks) の出番です。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/state.mdx",
    "content": "---\ntitle: '状態'\n---\n\n## 状態を保存するための一般的なビュー\n\nこの表は、どの状態保存タイプがあなたのユースケースに最適かを決定するためのガイドとして役立ちます：\n\n| フック             | タイプ                     | いつレンダリングされるか                   | スコープ                     |\n| ------------------ | -------------------------- | ------------------------------------------ | ---------------------------- |\n| [use_state]        | `T`                        | 値が設定されたとき                         | コンポーネントインスタンス内 |\n| [use_state_eq]     | `T: PartialEq`             | 異なる値が設定されたとき                   | コンポーネントインスタンス内 |\n| [use_reducer]      | `T: Reducible`             | リデューサーが呼び出されたとき             | コンポーネントインスタンス内 |\n| [use_reducer_eq]   | `T: Reducible + PartialEq` | リデューサーが呼び出され、結果が異なるとき | コンポーネントインスタンス内 |\n| [use_memo]         | `Deps -> T`                | 依存関係が変わったとき                     | コンポーネントインスタンス内 |\n| [use_callback]     | `Deps -> Callback<E>`      | 依存関係が変わったとき                     | コンポーネントインスタンス内 |\n| [use_mut_ref]      | `T`                        | -                                          | コンポーネントインスタンス内 |\n| グローバル静的定数 | `T`                        | -                                          | グローバル、どこでも使用可能 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/classes.mdx",
    "content": "---\ntitle: 'クラス'\ndescription: 'クラスを処理するための便利なマクロ'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## クラス\n\n`Classes` 構造体は、HTML クラスを処理するために使用できます。\n\n文字列をコレクションにプッシュすると、`Classes` は各クラスが一つの要素を持つことを保証します。単一の文字列が複数のクラスを含む場合でも同様です。\n\n`Classes` は、`Extend`（例：`classes1.extend(classes2)`）や `push()`（例：`classes1.push(classes2)`）を使用してマージすることもできます。`Into<Classes>` を実装している任意の型を既存の `Classes` にプッシュすることができます。\n\n`classes!` は、単一の `Classes` を作成するための便利なマクロです。その入力はカンマで区切られた式のリストを受け入れます。唯一の要件は、各式が `Into<Classes>` を実装していることです。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## クラスを受け入れるコンポーネント\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/components.mdx",
    "content": "---\ntitle: 'コンポーネント'\ndescription: 'コンポーネント階層を使用して複雑なレイアウトを作成する'\n---\n\n## 基本\n\nコンポーネントは `html!` マクロで使用できます：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // プロパティなし\n        <MyComponent />\n\n        // プロパティを使用\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // すべてのプロパティを一度に提供\n        <MyComponentWithProps ..props.clone() />\n\n        // 変数のプロパティを使用し、特定の値を上書き\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## ネスト\n\nコンポーネントの `Properties` に `children` フィールドがある場合、子コンポーネント/要素を受け入れることができます。\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` マクロは、各プロパティを個別に指定するのではなく、基本式を `..props` 構文で渡すことを可能にします。これは Rust の[関数的更新構文](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax)に似ています。\nこの基本式は、個別のプロパティを渡した後に現れる必要があります。\n`children` フィールドを持つ基本 props 式を渡す場合、`html!` マクロ内で渡された子要素は、props 内に既に存在する子要素を上書きします。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子要素は props.children を上書きします\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 参考例\n\n- [関数型 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [関数型ルーティング](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '条件レンダリング'\ndescription: 'HTMLで条件付きノードをレンダリングする！'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If ブロック\n\n条件付きでマークアップをレンダリングするには、それを `if` ブロックでラップします：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/elements.mdx",
    "content": "---\ntitle: '要素'\ndescription: 'HTML および SVG 要素のサポート'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM ノード\n\nYew で DOM ノードを手動で作成または管理する理由はたくさんあります。たとえば、管理されたコンポーネントと競合する可能性のある JS ライブラリとの統合などです。\n\n`web-sys` を使用すると、DOM 要素を作成して `Node` に変換できます。次に、`VRef` を使用して `Html` 値として使用できます：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // メモ化された関数、一度だけ実行されます\n    let node = use_memo(\n        (),\n        |_| {\n            // ドキュメントから div 要素を作成\n            let div: Element = document().create_element(\"div\").unwrap();\n            // コンテンツ、クラスなどを追加\n            div.set_inner_html(\"Hello, World!\");\n            // Element を Node に変換\n            let node: Node = div.into();\n            // その Node を Html 値として返す\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo は Rc ポインタを返すので、参照解除とクローンが必要です\n    (*node).clone()\n}\n\n```\n\n## 動的なタグ名\n\n高階コンポーネントを構築する際、タグ名が静的ではない状況に遭遇することがあります。例えば、`Title` コンポーネントがあり、レベル属性に応じて `h1` から `h6` までの任意の内容をレンダリングする場合です。大きなマッチ式を使用する代わりに、Yew は `@{name}` を使用してタグ名を動的に設定することを許可します。ここで、`name` は文字列を返す任意の式です。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 論理値属性\n\nいくつかのコンテンツ属性（例えば、checked、hidden、required）は論理値属性と呼ばれます。Yew では、論理値属性はブール値に設定する必要があります：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nこれは次の **HTML** と機能的に同等です：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n論理値属性を false に設定することは、その属性を使用しないことと同等です。論理式の値を使用することもできます：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nこれは次の **HTML** と機能的に同等です：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 文字列に似た属性\n\nいくつかの論理値属性に加えて、多くの文字列に似た HTML 属性を扱うことがあります。Yew には、文字列に似た値をコンポーネントに渡すためのいくつかのオプションがあります。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nそれらはすべて有効ですが、特にクローンを作成する必要がある場合や、別のコンポーネントに属性として渡す必要がある場合は、Yew のカスタム `AttrValue` を使用することをお勧めします。\n\n## HTML 要素のオプション属性\n\nほとんどの HTML 属性はオプションの値（Some(x) または None）を使用できます。これにより、属性がオプションとしてマークされている場合にその属性を省略できます。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n属性が `None` に設定されている場合、その属性は DOM に設定されません。\n\n## 関連例\n\n- [インライン HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/events.mdx",
    "content": "---\ntitle: 'イベント'\n---\n\n## 紹介\n\nYew は [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) クレートと統合されており、このクレートのイベントを使用します。以下の[表](#event-types)には、`html!` マクロで受け入れられるすべての `web-sys` イベントが一覧表示されています。\n\n下記の表に記載されていないイベントについても、[`Callback`](../function-components/callbacks.mdx) を追加してリッスンすることができます。詳細は[手動イベントリスナー](#manual-event-listener)を参照してください。\n\n## イベントタイプ\n\n:::tip\nすべてのイベントタイプは `yew::events` に再エクスポートされています。\n`yew::events` のタイプを使用することで、`web-sys` を手動でクレートに依存関係として追加するよりも、バージョン互換性を確保しやすくなります。\nYew が指定するバージョンと競合するバージョンを使用することがなくなります。\n:::\n\nイベントリスナーの名前は、`html` マクロでイベント `Callback` を追加する際に期待される名前です：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nイベント名はリスナー名から \"on\" プレフィックスを削除したもので、したがって `onclick` イベントリスナーは `click` イベントをリッスンします。ページの最後にある[完全なイベントリスト](#available-events)とそのタイプを参照してください。\n\n## イベントキャプチャ {#event-bubbling}\n\nYew がディスパッチするイベントは仮想 DOM 階層に従い、リスナーに向かってバブルアップします。現在、リスナーのバブルフェーズのみがサポートされています。仮想 DOM 階層は通常（ただし常にではありません）実際の DOM 階層と同じです。[ポータル](../../advanced-topics/portals)やその他の高度な技術を扱う際には、この違いが重要です。よく設計されたコンポーネントでは、直感的にイベントは子コンポーネントから親コンポーネントにバブルアップするはずです。これにより、`html!` で記述した階層がイベントハンドラによって観察される階層となります。\n\nイベントのバブルアップを避けたい場合は、アプリケーションを起動する前に以下のコードを呼び出すことができます\n\n```rust\nyew::set_event_bubbling(false);\n```\n\nアプリケーションを起動する*前に*。これによりイベント処理が高速化されますが、期待されるイベントを受信しないために一部のコンポーネントが動作しなくなる可能性があります。慎重に使用してください！\n\n## イベントデリゲート\n\n驚くかもしれませんが、イベントリスナーはレンダリングされた要素に直接登録されるわけではありません。代わりに、イベントは Yew アプリケーションのサブツリーのルートノードから委譲されます。ただし、イベントはそのネイティブ形式で渡され、合成形式は作成されません。これにより、HTML リスナーで予期されるイベントと Yew で発生するイベントとの間に不一致が生じる可能性があります。\n\n- [`Event::current_target`] はリスナーが追加された要素ではなく、Yew サブツリーのルートノードを指します。基になる `HtmlElement` にアクセスしたい場合は、[`NodeRef`](../function-components/node-refs.mdx) を使用してください。\n- [`Event::event_phase`] は常に [`Event::CAPTURING_PHASE`] です。内部的には、イベントはバブリングフェーズにあるかのように振る舞い、イベント伝播が再生され、イベントは[上位にバブルアップ](#event-bubbling)します。つまり、仮想 DOM 内の上位のイベントリスナーが下位のイベントリスナーの後にトリガーされます。現在、Yew はキャプチャリスナーをサポートしていません。\n\nこれも意味するところは、Yew によって登録されたイベントは通常、他のイベントリスナーよりも先にトリガーされるということです。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 型付きイベントターゲット\n\n:::caution\nこのセクションでは、**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** は常にイベントが発生した要素を指します。\n\nこれは**必ずしも** `Callback` が配置された要素を指すわけではありません。\n:::\n\nイベント `Callback` の中で、イベントのターゲットを取得したい場合があります。例えば、`change` イベントは何かが変更されたことを通知するだけで、具体的な情報を提供しません。\n\nYew では、正しい型でターゲット要素を取得する方法がいくつかあり、ここで順を追って説明します。イベント上の [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を呼び出すと、オプションの [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 型が返されますが、入力要素の値を知りたい場合にはあまり役に立たないかもしれません。\n\n以下のすべての方法で、同じ問題を解決します。これにより、方法の違いが明確になり、問題に対処することができます。\n\n**問題：**\n\n`<input>` 要素に `onchange` `Callback` があり、呼び出されるたびにコンポーネントに[更新](components#update) `Msg` を送信したいとします。\n\n`Msg` 列挙型は次のようになります：\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### `JsCast` の使用\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) クレートには便利なトレイトがあります：[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)。これにより、型が `JsCast` を実装している限り、型間の直接キャストが可能になります。慎重にキャストすることもできますが、これはランタイムチェックと `Option` や `Result` のロジックを処理することを伴います。また、強制的にキャストすることもできます。\n\nコードを見てみましょう：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# JsCast を呼び出すために wasm-bindgen が必要です\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // イベントが作成されたとき、ターゲットは未定義であり、ディスパッチされるときにのみターゲットが追加されます。\n            let target: Option<EventTarget> = e.target();\n            // イベントはバブルアップする可能性があるため、\n            // このリスナーは HtmlInputElement 型ではない子要素のイベントをキャッチする可能性があります。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // target が HtmlInputElement であることを理解している必要があります。\n        // そうでない場合、value を呼び出すと未定義の動作（UB）になります。\n        // ここでは、これが入力要素であることを確信しているため、チェックせずに適切な型に変換できます。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` が提供するメソッドは [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) と [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into) です。これらのメソッドを使用すると、`EventTarget` から [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html) への変換が可能になります。`dyn_into` メソッドは慎重で、実行時に型が実際に `HtmlInputElement` であるかどうかをチェックし、そうでない場合は `Err(JsValue)` を返します。[`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) は汎用型で、元のオブジェクトを返し、別の型への変換を再試行することができます。\n\nここで、危険なバージョンを使用するタイミングについて考えるかもしれません。上記のケースでは、子要素のない要素に `Callback` を設定しているため、ターゲットは同じ要素である必要があるため、安全です<sup>1</sup>。\n\n_<sup>1</sup> JS の領域に関わる限り、安全です。_\n\n### `TargetCast` の使用\n\n**[JsCast の使用](#using-jscast) を先に読むことを強くお勧めします！**\n\n:::note\n`TargetCast` は新しいユーザーが `JsCast` の動作を理解するために設計されていますが、範囲はイベントとそのターゲットに限定されています。\n\n`TargetCast` または `JsCast` を選択するのは純粋に個人の好みの問題であり、実際には `TargetCast` の実装と `JsCast` の機能は非常に似ています。\n:::\n\n`TargetCast` トレイトは `JsCast` の上に構築されており、イベントから型付きのイベントターゲットを取得するために特化されています。\n\n`TargetCast` は Yew の一部であるため、依存関係を追加せずにイベント上でトレイトメソッドを使用できますが、その動作は `JsCast` と非常に似ています。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // target が HtmlInputElement であることを理解している必要があります。\n        // そうでない場合、value を呼び出すと未定義の動作（UB）になります。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nもし `JsCast` についてすでに知っているか、このトレイトに精通している場合、`TargetCast::target_dyn_into` が `JsCast::dyn_into` に似ていることに気付くでしょうが、イベントのターゲットに特化しています。`TargetCast::target_unchecked_into` は `JsCast::unchecked_into` に似ているため、上記の `JsCast` に関するすべての警告が `TargetCast` にも適用されます。\n\n### `NodeRef` の使用\n\n[`NodeRef`](../function-components/node-refs.mdx) は、与えられたイベントを `Callback` に渡す代わりに使用できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`NodeRef` を使用すると、イベントを無視して `NodeRef::cast` メソッドを使用して `Option<HtmlInputElement>` を取得できます。これはオプションであり、`NodeRef` を設定する前に `cast` を呼び出すか、型が一致しない場合に `None` を返します。\n\n`NodeRef` を使用することで、常に `input_node_ref` にアクセスできるため、状態に `String` を送信する必要がないことがわかるかもしれません。したがって、次のようにすることができます：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // value に対して何かを行う\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nどの方法を選択するかは、コンポーネントと個人の好みによります。*推奨される*方法はありません。\n\n## 手動イベントリスナー\n\nYew の `html` マクロがサポートしていないイベントをリッスンしたい場合があります。サポートされているイベントのリストは[こちら](#event-types)を参照してください。\n\n手動で要素にイベントリスナーを追加するには、[`NodeRef`](../function-components/node-refs.mdx) を使用して、`use_effect_with` 内で [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) と [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API を使用してリスナーを追加します。\n\n以下の例では、架空の `custard` イベントにリスナーを追加する方法を示します。Yew がサポートしていないすべてのイベントやカスタムイベントは、[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) として表現できます。カスタム/サポートされていないイベントの特定のメソッドやフィールドにアクセスする必要がある場合は、[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) のメソッドを使用して必要な型に変換できます。\n\n### `Closure` を使用する（冗長バージョン）\n\n直接 `web-sys` と `wasm-bindgen` のインターフェースを使用するのは少し面倒かもしれません……なので、心の準備をしてください（[`gloo` のおかげで、より簡潔な方法があります](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 通常作成する Callback を作成\n                    let oncustard = Callback::from(move |_: Event| {\n                        // カスタードに対して何かを行う..\n                    });\n\n                    // Box<dyn Fn> から Closure を作成 - これは 'static である必要があります\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n`Closure` の詳細については、[wasm-bindgen ガイド](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html) を参照してください。\n\n### `gloo` を使用する（簡潔なバージョン）\n\nより便利な方法は、`gloo`、具体的には [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html) を使用することです。\nこれは `web-sys`、`wasm-bindgen` の高レベル抽象実装です。\n\n`gloo_events` は、イベントリスナーを作成および保存するために使用できる `EventListener` 型を提供します。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 通常作成する Callback を作成\n                    let oncustard = Callback::from(move |_: Event| {\n                        // カスタードに対して何かを行う..\n                    });\n\n                    // Box<dyn Fn> から Closure を作成 - これは 'static である必要があります\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n`EventListener` の詳細については、[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html) を参照してください。\n\n## 利用可能なイベントの完全なリスト {#available-events}\n\n| リスナー名                  | `web_sys` イベントの種類                                                              |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空のタグ (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロは常にルートノードを必要とします。この制限を回避するために、「空のタグ」（または fragments）を使用できます。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// エラー: ルート HTML 要素は1つだけ許可されます\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'HTML および SVG を生成するためのプロシージャルマクロ'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロを使用すると、宣言的に HTML および SVG コードを記述できます。これは、JavaScript で HTML に似たコードを記述できる拡張機能である JSX に似ています。\n\n**重要な注意点**\n\n1. `html! {}` マクロは 1 つのルート HTML ノードしか受け入れません（これを回避するには、[fragments](./fragments.mdx) または [iterators](./../html/lists.mdx) を使用できます）\n2. 空の `html! {}` 呼び出しは有効で、何もレンダリングしません\n3. リテラルは常に引用符で囲み、中括弧で囲む必要があります：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` マクロはすべてのタグ名を小文字に変換します。大文字の文字（特定の SVG 要素に必要な文字）を使用するには、[動的タグ名](concepts/html/elements.mdx#dynamic-tag-names) を使用してください：`html! { <@{\"myTag\"}></@> }`\n\n:::note\n`html!` マクロはコンパイラのデフォルトの再帰制限に達する可能性があります。コンパイル エラーが発生した場合は、クレートのルートに `#![recursion_limit=\"1024\"]` のような属性を追加して問題を解決してください。\n:::\n\n## タグ (Tags) 構造\n\nタグ (Tags) は HTML タグに基づいています。コンポーネント、要素、およびリストはすべてこのタグ構文に基づいています。\n\nタグは自己閉鎖 `<... />` であるか、開始タグごとに対応する終了タグが必要です。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 閉じタグがありません\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 閉じタグがありません\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n便利のために、通常は閉じタグが必要な要素も**自己閉じ**が許可されています。例えば、`html! { <div class=\"placeholder\" /> }` と記述することができます。\n:::\n\n複雑なネストされた HTML および SVG レイアウトを作成するのは依然として簡単です：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nもし、Rust コンパイラの開発者バージョンを使用して Yew をコンパイルする場合、マクロは一般的な落とし穴について警告します。もちろん、安定版コンパイラを使用してリリースビルドを行う必要があるかもしれません（例えば、組織のポリシーでそうする必要がある場合など）。しかし、安定版ツールチェーンを使用している場合でも、`cargo +nightly check` を実行すると、HTML コードを改善する方法がいくつか示されるかもしれません。\n\n現在、これらのリントは主にアクセシビリティに関連しています。リントに関するアイデアがあれば、[この問題](https://github.com/yewstack/yew/issues/1334)に自由にコメントしてください。\n\n## 属性とプロパティの指定\n\n属性は通常の HTML と同じ方法で要素に設定されます：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n属性は要素名の前に `~` を使用して指定されます：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n値がリテラルの場合、値を囲む中括弧は省略できます。\n\n:::\n\n:::note リテラルとは\n\nリテラルは、Rust のすべての有効な[リテラル式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)です。注意してください、[負の数は**リテラルではありません**](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)、したがって中括弧で囲む必要があります `{-6}`。\n\n:::\n\n:::note コンポーネント属性\nコンポーネント属性は Rust オブジェクトとして渡され、ここで説明されている要素のパラメータ (Attributes) / 属性 (Properties) とは異なります。\n[コンポーネント属性](../function-components/properties.mdx)で詳細を確認してください。\n:::\n\n### 特殊属性\n\nいくつかの特殊な属性があり、これらは直接 DOM に影響を与えるのではなく、Yew 仮想 DOM の指示として機能します。現在、2 つの特殊な属性があります：`ref` と `key`。\n\n`ref` は、基礎となる DOM ノードに直接アクセスして操作することを可能にします。詳細については、[Refs](../function-components/node-refs.mdx)を参照してください。\n\n一方、`key` は要素に一意の識別子を提供し、Yew が最適化のために使用できます。\n\n:::info\n[詳細はこちら](./html/lists)\n:::\n\n## 条件付きレンダリング\n\nRust の条件構造を使用して、条件付きでマークアップをレンダリングできます。現在、`if` と `if let` のみがサポートされています。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n条件付きレンダリングの詳細については、[条件付きレンダリング](./conditional-rendering.mdx)のセクションを参照してください。\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/lists.mdx",
    "content": "---\ntitle: 'リスト'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## イテレータ\n\nイテレータから HTML を構築する方法は 3 つあります：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` ループ\">\n主なアプローチは for ループを使用することです。これは Rust に既に存在する for ループと同じですが、2 つの重要な違いがあります：\n1. 通常の for ループは何も返せませんが、`html!` 内の for ループはノードのリストに変換されます。\n2. `break`、`continue` などの発散式は `html!` 内の for ループの本体では許可されていません。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` ブロック\">\nもう一つの方法は `for` キーワードを使用することです。これはネイティブの Rust 構文ではなく、HTML マクロによってイテレータを表示するために必要なコードを出力します。\nこの方法は、イテレータが既に計算されていて、マクロに渡すだけでよい場合に最初の方法より適しています。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` メソッド\">\n\n最後の方法は、イテレータの最終変換で `collect::<Html>()` を呼び出すことで、Yew が表示できるリストを返します。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## キー付きリスト\n\nキー付きリストは、すべての子要素にキーがある最適化されたリストです。\n`key` は Yew が提供する特別な属性で、HTML 要素やコンポーネントに一意の識別子を与え、Yew 内部での最適化に使用されます。\n\n:::caution\nキーは各リスト内で一意である必要があり、HTML の `id` のようにグローバルに一意である必要はありません。リストの順序に依存してはいけません。\n:::\n\nリストにキーを追加することを常にお勧めします。\n\n一意の `String`、`str`、または整数を特別な `key` 属性に渡すことでキーを追加できます。\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### パフォーマンスの最適化\n\nキー付きリストのパフォーマンス向上をテストするための[例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)があります。以下は簡単なテスト手順です：\n\n1. [オンラインデモ](https://examples.yew.rs/keyed_list)にアクセスします。\n2. 500個の要素を追加します。\n3. キーを無効にします。\n4. リストを反転します。\n5. \"最後のレンダリングにかかった時間 Xms\" を確認します（この記事の執筆時点では約60ms）。\n6. キーを有効にします。\n7. 再度リストを反転します。\n8. \"最後のレンダリングにかかった時間 Xms\" を確認します（この記事の執筆時点では約30ms）。\n\nこの記事の執筆時点では、500個のコンポーネントに対して速度が2倍に向上しました。\n\n### 原理の説明\n\n通常、リストを反復処理する際には、各リスト項目にキーを追加するだけで済みます。データの順序が変わる可能性があるためです。\nリストを再レンダリングする際に、キーは調整プロセスを高速化するために使用されます。\n\nキーがない場合、例えば `[\"bob\", \"sam\", \"rob\"]` を反復処理すると、最終的に以下のようなHTMLが生成されます：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n次のレンダリングでリストが `[\"bob\", \"rob\"]` に変更された場合、Yew は id=\"rob\" の要素を削除し、id=\"sam\" を id=\"rob\" に更新できます。\n\n各要素にキーを追加すると、初期の HTML は変わりませんが、変更後のリスト `[\"bob\", \"rob\"]` をレンダリングすると、Yew は2番目の HTML 要素のみを削除し、他の要素はそのまま残ります。キーを使用して要素を関連付けることができるためです。\n\nコンポーネントから別のコンポーネントに切り替える際に、両方に最高レンダリング要素として div がある場合にバグ/\"機能\" に遭遇した場合。\nYew はこれらの状況で最適化として既にレンダリングされた HTML div を再利用します。\nその div を再利用せずに再作成する必要がある場合は、異なるキーを追加することで再利用されなくなります。\n\n## さらなる読み物\n\n- [TodoMVC の例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [キー付きリストの例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [ルーティングの例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'リテラルと式'\n---\n\n## リテラル\n\n式が `Display` を実装する型に解決される場合、それらは文字列に変換され、[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) ノードとしてDOMに挿入されます。\n\n:::note\n文字列リテラルは `Text` ノードを作成し、ブラウザはそれを文字列として扱います。そのため、式に `<script>` タグが含まれていても、式を `<script>` ブロックでラップしない限り、XSS などのセキュリティ問題に遭遇することはありません。\n:::\n\nすべての表示テキストは式と見なされるため、`{}` ブロックで囲む必要があります。これは、Yew と通常の HTML 構文の最大の違いです。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 式\n\n`{}` ブロックを使用して、HTML 内に式を挿入できます。それらが `Html` に解決される限り。\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常、これらの式を関数やクロージャに抽出して、可読性を最適化することが意味があります：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/router.mdx",
    "content": "---\ntitle: 'ルーター (Router)'\ndescription: 'Yew の公式ルーターライブラリ'\n---\n\nシングルページアプリケーション (SPA) のルーターは、URL に基づいて異なるページを表示する処理を行います。リンクをクリックしたときに異なるリモートリソースを要求するデフォルトの動作とは異なり、ルーターはアプリケーション内の有効なルートを指すようにローカルで URL を設定します。その後、ルーターはこの変更を検出し、レンダリングする内容を決定します。\n\nYew は `yew-router` クレートでルーターサポートを提供します。使用を開始するには、依存関係を `Cargo.toml` ファイルに追加してください。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n必要なツールはすべて `yew_router::prelude` モジュールで提供されています。\n\n## 使用方法\n\nまず、`Route` を定義する必要があります。\n\nルートは `Routable` を派生する `enum` で定義されます。この列挙型は `Clone + PartialEq` を実装する必要があります。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` と `<Switch />` コンポーネントはペアで使用され、後者はブラウザの現在の URL に一致するパスのバリアントを見つけ、それを `render` コールバックに渡します。その後、コールバックがレンダリングする内容を決定します。パスが一致しない場合、ルーターは `not_found` 属性を持つパスにナビゲートします。指定されたルートがない場合、何もレンダリングされず、一致するルートがないことを示すメッセージがコンソールに記録されます。\n\nyew-router のほとんどのコンポーネント、特に `<Link />` と `<Switch />` は、ある Router コンポーネント（例： `<BrowserRouter />`）の（深い）子要素である必要があります。通常、アプリケーションには 1 つの Router しか必要なく、通常は最上位の `<App />` コンポーネントによって直ちにレンダリングされます。Router はコンテキストを登録し、これは Links と Switches の機能に必要です。以下に例を示します。\n\n:::caution\nブラウザ環境で `yew-router` を使用する場合、`<BrowserRouter />` を強く推奨します。他のルータータイプについては [API リファレンス](https://docs.rs/yew-router/) を参照してください。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### パスセグメント\n\nルーターは、動的および名前付きワイルドカードセグメントを使用してルートから情報を抽出することもできます。次に、`<Switch />` 内で投稿の ID にアクセスし、それを適切なコンポーネントにプロパティとして渡すことができます。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n`Post {id: String}` の代わりに通常の `Post` バリアントを使用することもできます。例えば、`Post` が別のルーターと一緒にレンダリングされる場合、そのフィールドは冗長になる可能性があります。詳細については、以下の[ネストされたルーター](#nested-router)セクションを参照してください。\n:::\n\nフィールドは `Route` 列挙型の一部として `Clone + PartialEq` を実装する必要があることに注意してください。また、シリアル化と逆シリアル化のために `std::fmt::Display` と `std::str::FromStr` を実装する必要があります。整数、浮動小数点数、および文字列などのプリミティブ型はこれらの要件を既に満たしています。\n\nパスの形式が一致しても、逆シリアル化が失敗した場合（`FromStr` に基づく）、ルーターはルートが一致しないと見なし、見つからないルートをレンダリングしようとします（または、見つからないルートが指定されていない場合は空白ページをレンダリングします）。\n\n以下の例を参照してください：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch 関数は News と id をレンダリングします。ここでは省略されています。\n```\n\nセグメントが 255 を超えると、`u8::from_str()` は失敗し、`ParseIntError` を返します。この場合、ルーターはルートが一致しないと見なします。\n\n![ルーターの逆シリアル化失敗の動作](/img/router-deserialization-failure-behavior.gif)\n\nルーティング構文やパラメータのバインディング方法の詳細については、[route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params) を参照してください。\n\n### 位置 (Location)\n\nルーターはコンテキストを介して一般的な `Location` 構造体を提供し、ルート情報にアクセスするために使用できます。これらはフックまたは `ctx.link()` 上の便利な関数を介して取得できます。\n\n### ナビゲーション\n\n`yew_router` はナビゲーションを処理するためのいくつかのツールを提供します。\n\n#### リンク\n\n`<Link />` は `<a>` 要素としてレンダリングされ、`onclick` イベントハンドラは [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) を呼び出し、ターゲットページを履歴にプッシュして必要なページをレンダリングします。これはシングルページアプリケーションに期待される動作です。通常のアンカー要素のデフォルトの `onclick` はページをリロードします。\n\n`<Link />` コンポーネントはその子要素を `<a>` 要素に渡します。これはアプリ内ルーティングのための `<a/>` の代替として考えることができます。違いは、`href` の代わりに `to` 属性を提供する必要があることです。使用例は以下の通りです：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n構造体変数も正常に動作します：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### ナビゲーションインターフェース\n\nナビゲーター API は、関数コンポーネントと構造体コンポーネントの両方で提供されます。これにより、コールバックがルートを変更できるようになります。どちらの場合でも、`Navigator` インスタンスを取得してルートを操作できます。\n\n##### 関数コンポーネント\n\n関数コンポーネントの場合、基礎となるナビゲータープロバイダーが変更されると、`use_navigator` フックはコンポーネントを再レンダリングします。\n以下は、クリック時に `Home` ルートにナビゲートするボタンを実装する例です。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\nここでの例では `Callback::from` を使用しています。ターゲットルートがコンポーネントのルートと同じになる可能性がある場合、または安全のために、通常のコールバックを使用してください。例えば、各ページにロゴボタンがあり、そのボタンをクリックするとホームに戻るとします。ホームページでそのボタンを2回クリックすると、同じHomeルートがプッシュされ、`use_navigator` フックが再レンダリングをトリガーしないため、コードがクラッシュします。\n:::\n\n現在の位置をスタックに新しい位置としてプッシュするのではなく置き換えたい場合は、`navigator.push()` の代わりに `navigator.replace()` を使用してください。\n\n`navigator` はコールバックに移動する必要があるため、他のコールバックで再利用できないことに気付くかもしれません。幸いなことに、`navigator` は `Clone` を実装しているため、異なるルートに対して複数のボタンを設定する方法は次のとおりです：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 構造体コンポーネント\n\n構造体コンポーネントの場合、`ctx.link().navigator()` API を使用して `Navigator` インスタンスを取得できます。残りの部分は関数コンポーネントの場合と同じです。以下は、単一のボタンをレンダリングするビュー関数の例です。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### リダイレクト\n\n`yew-router` は prelude に `<Redirect />` コンポーネントも提供しています。これはナビゲーター API と同様の効果を実現するために使用できます。このコンポーネントは、ターゲットルートとして `to` 属性を受け取ります。`<Redirect/>` がレンダリングされると、ユーザーは指定されたルートにリダイレクトされます。以下はその例です：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // `use_user` フックを使用してユーザーを取得\n    let user = match use_user() {\n        Some(user) => user,\n        // ユーザーが `None` の場合、ログインページにリダイレクト\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 実際のページ内容\n}\n```\n\n:::tip `Redirect` と `Navigator` の選択方法\nNavigator API はコールバック内でルートを操作する唯一の方法です。\n一方、`<Redirect />` はコンポーネント内の戻り値として使用できます。また、[ネストされたルーター](#nested-router)の switch 関数など、他の非コンポーネントコンテキストでも `<Redirect />` を使用することができます。\n:::\n\n### 変更のリスニング\n\n#### 関数コンポーネント\n\n`use_location` と `use_route` フックを使用できます。提供された値が変更されると、コンポーネントが再レンダリングされます。\n\n#### 構造体コンポーネント\n\nルートの変更に応答するために、`ctx.link()` の `add_location_listener()` メソッドにコールバッククロージャを渡すことができます。\n\n:::note\n位置リスナーが削除されると、それは登録解除されます。ハンドルをコンポーネントの状態に保存することを確認してください。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // イベントを処理する\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` と `ctx.link().route::<R>()` も、一度だけ位置とルートを取得するために使用できます。\n\n### クエリパラメータ\n\n#### ナビゲーション時にクエリパラメータを指定する\n\n新しいルートにナビゲートする際にクエリパラメータを指定するには、`navigator.push_with_query` または `navigator.replace_with_query` 関数を使用します。これは `serde` を使用してパラメータを URL のクエリ文字列にシリアル化するため、`Serialize` を実装している任意の型を渡すことができます。最も簡単な形式は文字列ペアを含む `HashMap` です。\n\n#### 現在のルートのクエリパラメータを取得する\n\nクエリパラメータを取得するには、`location.query` を使用します。これは `serde` を使用して URL のクエリ文字列からパラメータを逆シリアル化します。\n\n## ネストされたルーター\n\nアプリケーションが大きくなると、ネストされたルーターが役立つ場合があります。次のルーター構造を考えてみましょう：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nネストされた `SettingsRouter` は、すべての `/settings` で始まる URL を処理します。また、一致しない URL をメインの `NotFound` ルートにリダイレクトします。したがって、`/settings/gibberish` は `/404` にリダイレクトされます。\n\n:::caution\n\nこのインターフェースはまだ開発中であり、このように記述する方法は最終決定されていません。\n\n:::\n\n以下のコードで実装できます：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### ベースパス (Basename)\n\n`yew-router` を使用してベースパス (Basename) を定義できます。\nベースパスはすべてのルートの共通プレフィックスです。ナビゲーター API と `<Switch />` コンポーネントはどちらもベースパスの設定をサポートしています。プッシュされるすべてのルートにはベースパスのプレフィックスが追加され、すべてのスイッチはパスを `Routable` に解析する前にベースパスを削除します。\n\nRouter コンポーネントにベースパス属性が提供されていない場合、HTML ファイルの `<base />` 要素の href 属性を使用し、HTML ファイルに `<base />` 要素がない場合は `/` にフォールバックします。\n\n## 関連例\n\n- [ルーター](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## インターフェースリファレンス\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/suspense.mdx",
    "content": "---\ntitle: 'サスペンス (Suspense)'\ndescription: 'データ取得のためのサスペンス'\n---\n\nサスペンス (Suspense) は、タスクが完了するまでコンポーネントのレンダリングを一時停止し、その間にフォールバック（プレースホルダー）UI を表示する方法です。\n\nこれは、サーバーからデータを取得したり、プロキシがタスクを完了するのを待ったり、他のバックグラウンド非同期タスクを実行したりするために使用できます。\n\nサスペンスが表示される前に、データ取得は通常、コンポーネントのレンダリング後（レンダリング時取得）またはレンダリング前（取得後レンダリング）に発生します。\n\n### レンダリングしながらダウンロード\n\nサスペンス (Suspense) は、新しい方法を提供し、コンポーネントがレンダリング中にデータリクエストを発行できるようにします。コンポーネントがデータリクエストを発行すると、レンダリングプロセスが一時停止され、リクエストが完了するまでフォールバック UI が表示されます。\n\nサスペンスを使用するには、フック (Hook) を使用することをお勧めします。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n上記の例では、`use_user` フックはユーザー情報の読み込み中にコンポーネントのレンダリングを一時停止し、`user` が読み込まれる前に `Loading...` プレースホルダーを表示します。\n\nコンポーネントのレンダリングを一時停止するフックを定義するには、`SuspensionResult<T>` を返す必要があります。コンポーネントが一時停止する必要がある場合、フックは `Err(Suspension)` を返すべきであり、ユーザーはそれを `?` でアンパックする必要があります。これにより、それが `Html` に変換されます。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // ユーザーが読み込まれたら、それを Ok(user) として返します。\n        Some(user) => Ok(user),\n        None => {\n            // ユーザーがまだ読み込まれていない場合、`Suspension` を作成し、\n            // データの読み込みが完了したときに `SuspensionHandle::resume` を呼び出します。\n            // これにより、コンポーネントは自動的に再レンダリングされます。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### サスペンスフック (Hook) の実装に関する注意事項\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) は 2 つの値を返します：サスペンスコンテキスト自体とサスペンスハンドル。後者はサスペンスされたコンポーネントを再レンダリングするタイミングを管理し、2 つの方法で操作できます：\n\n1. その [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) メソッドを呼び出す。\n2. ハンドルを破棄する。\n\n:::danger\n\nサスペンスハンドルは、新しいデータを受け取ってコンポーネントを更新するまで保存する必要があります。そうしないと、サスペンスされたコンポーネントが無限再レンダリングループに入り、パフォーマンスに影響を与えます。\n上記の例では、サスペンスハンドルはクロージャに移動し、`on_load_user_complete` に渡されることで保存されます。\n仮想ユーザーが読み込まれると、クロージャが呼び出され、`handle.resume()` が呼び出され、サスペンスコンテキストに関連するコンポーネントが再レンダリングされます。\n\n:::\n\n# 完全な例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 省略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 省略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // ユーザーが読み込まれたら、それを Ok(user) として返します。\n        Some(user) => Ok(user),\n        None => {\n            // ユーザーがまだ読み込まれていない場合、`Suspension` を作成し、\n            // データの読み込みが完了したときに `SuspensionHandle::resume` を呼び出します。\n            // これにより、コンポーネントは自動的に再レンダリングされます。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 構造体コンポーネントでプレースホルダーを使用する\n\n構造体コンポーネントを直接サスペンドすることはできません。しかし、関数コンポーネントを[高階コンポーネント](../advanced-topics/struct-components/hoc)として使用し、プレースホルダーに基づいたデータ取得を実現することができます。\n\nYew リポジトリの[プレースホルダーの例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)は、このコンポーネントの使用方法を示しています。\n\n## 関連例\n\n- [プレースホルダー](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'サンプルアプリケーションの構築'\n---\n\n環境が整ったら、基本的な Yew アプリケーションに必要なテンプレートを使用するか、小さなプロジェクトを手動で設定することができます。\n\n## テンプレートを使用して迅速に開始\n\n[`cargo-generate`](https://github.com/cargo-generate/cargo-generate) のインストール手順に従ってツールをインストールし、次のコマンドを実行します：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手動でアプリケーションを設定する\n\n### プロジェクトの作成\n\nまず、新しい cargo プロジェクトを作成してください。\n\n```bash\ncargo new yew-app\n```\n\n新しく作成したディレクトリを開きます。\n\n```bash\ncd yew-app\n```\n\n### Hello World サンプルを実行する\n\nRust 環境が正しく設定されているかを確認するために、`cargo run` を使用して初期プロジェクトを実行します。\"Hello World!\" メッセージが表示されるはずです。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### プロジェクトを Yew Web アプリケーションに設定する\n\nこのシンプルなコマンドラインアプリケーションを基本的な Yew Web アプリケーションに変換するために、いくつかの変更が必要です。\n\n#### Cargo.toml の更新\n\n依存関係リストに `yew` を追加します。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n# 開発バージョンの Yew\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\nアプリケーションを構築するだけの場合は、`csr` 特性のみが必要です。これにより、`Renderer` とクライアントサイドレンダリングに関連するすべてのコードが有効になります。\n\nライブラリを作成している場合は、この特性を有効にしないでください。クライアントサイドレンダリングロジックがサーバーサイドレンダリングパッケージに含まれることになります。\n\nテストやサンプルのために Renderer が必要な場合は、`dev-dependencies` で有効にするべきです。\n\n:::\n\n#### main.rs の更新\n\nテンプレートを生成し、クリック時に値を更新するボタンをレンダリングする `App` という名前のルートコンポーネントを設定する必要があります。以下のコードで `src/main.rs` の内容を置き換えます。\n\n:::note\n`main` 関数内の `yew::Renderer::<App>::new().render()` 呼び出しは、アプリケーションを起動し、ページの `<body>` タグにマウントします。動的なプロパティを使用してアプリケーションを起動したい場合は、`yew::Renderer::<App>::with_props(..).render()` を使用できます。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### index.html の作成\n\n最後に、アプリケーションのルートディレクトリに `index.html` ファイルを追加します。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## アプリケーションの表示\n\n以下のコマンドを実行して、ローカルでアプリケーションをビルドおよび提供します。\n\n```bash\ntrunk serve\n```\n\n:::info\n`--open` オプションを追加して、デフォルトのブラウザを開くことができます：`trunk serve --open`。\n:::\n\nTrunk は、ソースコードファイルを変更するたびにアプリケーションをリアルタイムで再構築します。\nデフォルトでは、サーバーはアドレス '127.0.0.1' のポート '8080' でリッスンします => [http://localhost:8080](http://127.0.0.1:8080)。\nこの設定を変更するには、次のファイルを作成して必要に応じて編集してください：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# ローカルネットワーク上のリッスンアドレス\naddress = \"127.0.0.1\"\n# 広域ネットワーク上のリッスンアドレス\n# address = \"0.0.0.0\"\n# リッスンするポート\nport = 8000\n```\n\n## おめでとうございます\n\nこれで、Yew 開発環境の設定が完了し、最初の Web アプリケーションを構築できました。\n\nこのアプリケーションを試してみて、さらに学習するために[サンプル](./examples.mdx)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'エディタの設定'\ndescription: 'コードエディタの設定'\n---\n\n:::important 改善ドキュメント\n異なるエディタを使用していますか？おすすめがあれば、選択したエディタの説明を自由に追加してください。\n:::\n\n## コンポーネント作成のためのテンプレートを追加\n\n### JetBrains IDEs\n\n1. ナビゲーションバーから順に File | Settings | Editor | Live Templates をクリックします。\n2. Rust を選択し、+ アイコンをクリックして新しい Live Template を追加します。\n3. 必要に応じて名前と説明を入力します。\n4. 以下のコードスニペットをテンプレートテキスト部分に貼り付けます。\n5. 右下の適用範囲を変更し、Rust > Item > Module を選択します。\n\n関数型コンポーネントの場合、以下のテンプレートを使用します。\n\n- (オプション) 変数を編集し、`tag` に適切なデフォルト値（例：\"div\"）を設定します。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n構造体コンポーネントの場合、以下のより複雑なテンプレートを使用できます。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. ナビゲーションバーから順に File > Preferences > User Snippets をクリックします。\n2. 設定言語として Rust を選択します。\n3. 以下の JSON ファイルにコードスニペットを追加します。\n\n````json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n## `html!` マクロのサポート\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 拡張機能\n\n> これは**進行中の**、**コミュニティが維持している**プロジェクトです！[詳細を確認し、関連するバグ報告/問題/質問を直接拡張機能のリポジトリに送信してください](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 拡張機能は [VSC Marketplace で見つけることができます](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)、シンタックスハイライト、リネーム、ホバーなどの機能を提供します。\n\nEmmet サポートは直接使用できるはずですが、できない場合は `settings.json` ファイルを編集してください：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n````\n\n### Neovim\n\n#### Lazyvim\n\n> 以下の設定は [LazyVim](https://www.lazyvim.org) 設定および lazy.vim プラグインに適用されます。`lua/plugins/nvim-lspconfig.lua` にファイルを作成するか、既存の `lspconfig` を更新してください：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/examples.mdx",
    "content": "---\ntitle: '例'\n---\n\nYew リポジトリには多くの[例]（メンテナンス状態はさまざま）があります。\nフレームワークのさまざまな機能を理解するために、それらを参照することをお勧めします。\n無視されがちで助けが必要な場合に備えて、プルリクエストや問題も歓迎します ♥️。\n\n詳細については、[README] を参照してください。\n\n:::note\nほとんどの例には、https://examples.yew.rs/< example_name > で見つけることができるオンラインデプロイがあります。\nそれぞれのサブフォルダーの README ページでバッジをクリックして、オンラインデモに移動します。\n:::\n\n[例のリスト]: https://github.com/yewstack/yew/tree/master/examples\n[例のドキュメント README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/getting-started/introduction.mdx",
    "content": "---\ntitle: '始めに'\n---\n\nYew アプリケーションをコンパイル、ビルド、パッケージ、およびデバッグするためにいくつかのツールが必要です。最初に、[Trunk](https://trunkrs.dev/) を使用することをお勧めします。Trunk は Rust 用の WASM Web アプリケーションパッケージツールです。\n\n## Rust のインストール\n\nRust をインストールするには、[公式の手順](https://www.rust-lang.org/tools/install) に従ってください。\n\n:::important\nYew がサポートする最低 Rust バージョン（MSRV）は `1.84.0` です。古いバージョンではコンパイルできません。`rustup show`（「active toolchain」の下）または `rustc --version` を使用してツールチェーンのバージョンを確認できます。ツールチェーンを更新するには、`rustup update` を実行してください。\n:::\n\n## WebAssembly ターゲットのインストール\n\nRust は異なる「ターゲット」（例えば異なるプロセッサ）に対してソースコードをコンパイルできます。ブラウザベースの WebAssembly 用のコンパイルターゲットは `wasm32-unknown-unknown` と呼ばれます。以下のコマンドは、開発環境に WebAssembly ターゲットを追加します。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Trunk のインストール\n\nTrunk は、デプロイとパッケージ管理に推奨されるツールであり、ドキュメントやサンプル全体で使用されています。\n\n```shell\n# 注意：これはすべての内容をゼロからコンパイルするため、インストールに時間がかかる場合があります\n# Trunk は多くの主要なパッケージマネージャーに対して事前構築されたバイナリを提供しています\n# 詳細については、https://trunkrs.dev/#install を参照してください\ncargo install --locked trunk\n```\n\n### 他のオプション\n\nTrunk の他にも、Yew アプリケーションをパッケージ化するための他のオプションがあります。以下のオプションのいずれかを試してみることをお勧めします：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/)（まだ初期開発段階です）\n\n## 次のステップ\n\n開発環境の設定が完了したら、ドキュメントの読み進めを続けることができます。実践を通じて学ぶのが好きな方は、[チュートリアル](../tutorial)をチェックすることをお勧めします。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: '0.22.0 から 0.23.0 へ'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` が同一ディスパッチで再レンダリングしなくなりました\n\n`use_reducer` はリデューサーが同じ `Rc` を返した場合（ポインタの同一性で判定）、再レンダリングをスキップするようになりました。以前は、すべてのディスパッチで再レンダリングが発生していました。\n\nリデューサーに `self` をそのまま返すコードパスがあり、それによる再レンダリングに依存していた場合は、`use_force_update` に置き換えてください:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"変更前\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // 0.23 ではこれは再レンダリングを発生させません!\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"リフレッシュ\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"変更後\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"リフレッシュ\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: '0.4.0 から 0.5.0 へ'\n---\n\n破壊的変更はありません。`Cargo.toml` で yew-agent を 0.5.0 に更新してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: '0.19.0 から 0.20.0 へ'\n---\n\n破壊的変更はありません。`Cargo.toml` で yew-router を 0.20.0 に更新してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nYew に CSS サポートを統合する最良の方法についての議論は、こちらで見つけることができます：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\nここには、Yew に CSS サポートを統合する最良の方法についての多くの議論が含まれています。\n\n現在、私たちが採用している方法は、開発者が最も人気のあるシステムを採用する前に多くのシステムを構築することを奨励することです。\n\nコミュニティは現在、プロジェクトにスタイルを追加するためのいくつかのプロジェクトを開発しています。以下はその一部です：\n\n#### コンポーネントライブラリ\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - JavaScript 依存なしの Yew スタイルフレームワーク。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - マテリアルデザインコンポーネント。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS コンポーネント。\n- [Yewtify](https://github.com/yewstack/yewtify) – Yew で Vuetify フレームワークの機能を実現。\n\n#### スタイルソリューション\n\n- [stylist](https://github.com/futursolo/stylist-rs) - WebAssembly アプリケーション用の CSS-in-Rust スタイルソリューション。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind ユーティリティクラス。\n\n:::important ドキュメントの改善\nYew にスタイルを追加するプロジェクトを開発している場合は、このリストに自分を追加する PR を提出してください！\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/more/debugging.mdx",
    "content": "---\ntitle: 'デバッグ'\n---\n\n## パニック (Panics)\n\nYew はブラウザのコンソールにパニックログを自動的に出力します。\n\n## コンソールログ\n\nJavaScript では、`console.log()` を使用してブラウザのコンソールに出力します。以下は Yew のいくつかのオプションです。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` クレートは [`log`](https://crates.io/crates/log) クレートと統合されており、ログレベル、ソース行、ファイル名をブラウザのコンソールに送信します。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nこのクレートは Gloo の一部で、ブラウザ API の Rust ラッパーを提供します。`log!` マクロは `JsValue` を直接受け入れることができ、`wasm_logger` よりも使いやすいです。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` は [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) と一緒に使用でき、メッセージをブラウザのコンソールに出力します。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## コンポーネントライフサイクルのデバッグ\n\n[`tracing`](https://crates.io/crates/tracing) は、コンポーネントのライフサイクルに関連するイベント情報を収集するために使用できます。`tracing` には `log` サポートの機能フラグもあり、`wasm-logger` とうまく統合できます。\n\n[コンパイル時フィルタ](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) は、詳細度を調整したりログ記録を無効にしたりするために使用できます。これにより、より小さな Wasm ファイルが生成されるはずです。\n\n## ソースマップ (Source Maps)\n\n[ソースマップ](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) をサポートするいくつかの方法がありますが、いくつかの設定が必要です。\n\n## 過去の記事\n\n以下は、Rust における WebAssembly デバッグの現状に関する過去の記事です。興味深い読み物かもしれません。\n\n\\[2019 年 12 月\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> これらの作業にはまだ多くのことが残されています。例えば、ツールの面では、Emscripten（Binaryen）と wasm-pack（wasm-bindgen）は、それらが実行する変換に対して DWARF 情報を更新することをまだサポートしていません。\n\n\\[2020 年\\] [Rust Wasm デバッグガイド](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 残念ながら、WebAssembly のデバッグ機能はまだ未成熟です。ほとんどの Unix システムでは、[DWARF](http://dwarfstd.org/) が実行中のプログラムのソースレベルの検査に必要な情報をエンコードするために使用されますが、Windows では同様の情報をエンコードする代替フォーマットがあります。しかし、現在のところ、WebAssembly には対応するフォーマットがありません。\n\n\\[2019 年\\] [Rust Wasm ロードマップ](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> デバッグは難しいです。なぜなら、多くの状況がこの作業グループの管理下にないからです。これは、WebAssembly の標準化機関やブラウザ開発者ツールを実装する人々に依存しています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/more/deployment.mdx",
    "content": "---\ntitle: 'デプロイ'\ndescription: 'Yew アプリケーションのデプロイ'\n---\n\nYew アプリケーションをサーバーにデプロイする準備ができたら、いくつかのデプロイオプションがあります。\n\n`trunk build --release` は、リリースモードでアプリケーションをビルドします。HTTP サーバーを設定して、サイトにアクセスしたときに `index.html` を提供し、静的パス（例：`index_<hash>.js` および `index_bg_<hash>.wasm`）のリクエストに対して trunk が生成した dist ディレクトリから適切なコンテンツを提供する必要があります。\n\n:::important `trunk serve --release` について\n`trunk serve --release` を使用してアプリケーションを提供しないでください。\nこれは開発中にリリースビルドをテストするためだけに使用されるべきです。\n:::\n\n## サーバー設定\n\n### `index.html` をフォールバックとして提供する\n\nアプリケーションが [Yew ルーター](concepts/router.mdx) を使用している場合、存在しないファイルへのリクエスト時にサーバーが `index.html` を返すように設定する必要があります。\n\nYew ルーターを使用するアプリケーションは [シングルページアプリケーション (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA) として構築されています。ユーザーが実行中のクライアントから URL にナビゲートすると、ルーターが URL を解釈してそのページにルーティングします。\n\nしかし、ページをリフレッシュしたり、アドレスバーに URL を入力したりすると、これらの操作は実行中のアプリケーションではなく、ブラウザー自体によって処理されます。ブラウザーはその URL を直接サーバーにリクエストし、ルーターをバイパスします。誤って設定されたサーバーは 404 - 見つかりません 状態を返します。\n\n`index.html` を返すことで、アプリケーションは通常通りにロードされ、ルーターがルート `/show/42` を認識して適切なコンテンツを表示するまで、リクエストが `/` であるかのように動作します。\n\n### Web Assembly リソースに正しい MIME タイプを設定する\n\nWASM ファイルは `application/wasm` MIME タイプで [Content-Type ヘッダー](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) を設定する必要があります。\n\nほとんどのサーバーとホスティングサービスはデフォルトでこれを行います。サーバーがこれを行わない場合は、そのドキュメントを参照してください。ほとんどの Web ブラウザーでは、誤った MIME タイプは次のようなエラーを引き起こします：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 相対パスのビルド\n\nデフォルトでは、trunk はサイトが `/` で提供されると仮定し、それに応じてサイトをビルドします。この動作は、`index.html` ファイルに `<base data-trunk-public-url />` を追加することで上書きできます。Trunk はこのタグを書き換えて、`--public-url` に渡された値を含めます。Yew ルーターは `<base />` の存在を自動的に検出し、適切に処理します。\n\n## 環境変数を使用して動作をカスタマイズする\n\n通常、環境変数を使用してビルド環境をカスタマイズします。アプリケーションがブラウザで実行されるため、実行時に環境変数を読み取ることはできません。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) マクロは、コンパイル時に環境変数の値を取得できます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/more/roadmap.mdx",
    "content": "---\ntitle: 'ロードマップ'\ndescription: 'Yew フレームワークの計画機能ロードマップ'\n---\n\n## 優先順位\n\nフレームワークの今後の機能と重点の優先順位はコミュニティによって決定されます。\n2020 年春に、プロジェクトの方向性に関するフィードバックを収集するために開発者調査を実施しました。\n調査の概要は [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) で確認できます。\n\n:::note\nすべての主要なイニシアチブのステータスは Yew Github の [プロジェクトボード](https://github.com/yewstack/yew/projects) で追跡できます。\n:::\n\n## 重点\n\n1. 最も人気のある機能\n2. プロダクションレディ\n3. ドキュメント\n4. 痛点\n\n### 最も人気のある機能\n\n1. [関数コンポーネント](https://github.com/yewstack/yew/projects/3)\n2. [コンポーネントライブラリ](https://github.com/yewstack/yew/projects/4)\n3. より良い状態管理\n4. [サーバーサイドレンダリング](https://github.com/yewstack/yew/projects/5)\n\n### プロダクションレディに必要な問題\n\n- Yew のテストカバレッジを向上させる\n- バイナリサイズを小さくする\n- [パフォーマンスベンチマーク](https://github.com/yewstack/yew/issues/5)\n\n### ドキュメント\n\n- チュートリアルを作成する\n- プロジェクト設定を簡素化する\n\n### 痛点\n\n- [コンポーネントテンプレート](https://github.com/yewstack/yew/issues/830)\n- [エージェント](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/more/testing.mdx",
    "content": "---\ntitle: 'アプリケーションのテスト'\ndescription: 'アプリケーションをテストする'\n---\n\n:::info\nコンポーネントのテストをより簡単にするために努力していますが、現在進行中です。\n\n[浅いレンダリング](https://github.com/yewstack/yew/issues/1413) のサポートは GitHub リポジトリで見つけることができます。\n:::\n\n## スナップショットテスト\n\nYew はコンポーネントのスナップショットテストを容易にするために `yew::tests::layout_tests` モジュールを提供しています。\n\n:::important ドキュメントの改善\nスナップショットテストのドキュメントを改善するための助けが必要です。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM ワーキンググループは [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) というクレートを維持しています。\nこれにより、組み込みの `#[test]` プロシージャマクロに似た方法でブラウザ内でテストを実行できます。\nこのモジュールの詳細については、[Rust Wasm ワーキンググループのドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current/tutorial/index.mdx",
    "content": "---\ntitle: 'チュートリアル'\nslug: /tutorial\n---\n\n## 紹介\n\nこの実践チュートリアルでは、Yew を使用して Web アプリケーションを構築する方法を学びます。\n**Yew** は、[WebAssembly](https://webassembly.org/) を使用してフロントエンド Web アプリケーションを構築するためのモダンな [Rust](https://www.rust-lang.org/) フレームワークです。\nYew は Rust の強力な型システムを活用し、再利用可能で保守しやすく、良好に構造化されたアーキテクチャを奨励します。\nRust の [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html) と呼ばれるライブラリのエコシステムは、状態管理などの一般的なパターンのためのコンポーネントを提供します。\nRust のパッケージマネージャー [Cargo](https://doc.rust-lang.org/cargo/) を使用すると、Yew などの多くの crate を [crates.io](https://crates.io) から利用できます。\n\n### 構築する内容\n\nRustconf は、Rust コミュニティが毎年開催する星間集会です。\nRustconf 2020 には多くの講演があり、大量の情報が提供されました。\nこの実践チュートリアルでは、他の Rustaceans がこれらの講演を理解し、1つのページから視聴できるようにする Web アプリケーションを構築します。\n\n## セットアップ\n\n### 前提条件\n\nこのチュートリアルは、Rust に精通していることを前提としています。Rust の初心者である場合、無料の [Rust 本](https://doc.rust-lang.org/book/ch00-00-introduction.html) は初心者にとって素晴らしい出発点であり、経験豊富な Rust 開発者にとっても優れたリソースです。\n\n最新バージョンの Rust がインストールされていることを確認するには、`rustup update` を実行するか、[Rust をインストール](https://www.rust-lang.org/tools/install) します。\n\nRust をインストールした後、Cargo を使用して以下のコマンドを実行し、`trunk` をインストールします：\n\n```bash\ncargo install trunk\n```\n\nWASM のビルドターゲットも追加する必要があります。次のコマンドを実行します：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### プロジェクトの設定\n\nまず、新しい cargo プロジェクトを作成します：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nRust 環境が正しく設定されていることを確認するために、cargo ビルドツールを使用して初期プロジェクトを実行します。\nビルドプロセスの出力に続いて、期待される \"Hello, world!\" メッセージが表示されるはずです。\n\n```bash\ncargo run\n```\n\n## 最初の静的ページ\n\nこのシンプルなコマンドラインアプリケーションを基本的な Yew Web アプリケーションに変換するために、いくつかの変更が必要です。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\nアプリケーションを構築するだけの場合は、`csr` 特性のみが必要です。これにより、`Renderer` とクライアントサイドレンダリングに関連するすべてのコードが有効になります。\n\nライブラリを作成している場合は、この特性を有効にしないでください。クライアントサイドレンダリングロジックがサーバーサイドレンダリングパッケージに含まれてしまいます。\n\nテストやサンプルのために Renderer が必要な場合は、`dev-dependencies` で有効にするべきです。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nそれでは、プロジェクトのルートディレクトリに `index.html` を作成しましょう。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 開発サーバーの起動\n\n以下のコマンドを実行して、アプリケーションをビルドし、ローカルで提供します。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n`--open` オプションを削除して、`trunk serve` を実行した後にデフォルトのブラウザを開かないようにします。\n:::\n\nTrunk は、ソースコードファイルを変更するたびにアプリケーションをリアルタイムで再構築します。\nデフォルトでは、サーバーはアドレス '127.0.0.1' のポート '8080' でリッスンします => [http://localhost:8080](http://127.0.0.1:8080)。\nこの設定を変更するには、次のファイルを作成して必要に応じて編集します：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# ローカルネットワーク上のリッスンアドレス\naddress = \"127.0.0.1\"\n# 広域ネットワーク上のリッスンアドレス\n# address = \"0.0.0.0\"\n# リッスンするポート\nport = 8000\n```\n\nもし興味があれば、`trunk help` および `trunk help <subcommand>` を実行して、進行中のプロセスの詳細についてさらに学ぶことができます。\n\n### おめでとうございます\n\nこれで、Yew 開発環境を正常にセットアップし、最初の Yew Web アプリケーションを構築しました。\n\n## HTML の構築\n\nYew は Rust のプロシージャルマクロを利用しており、JSX（JavaScript の拡張で、JavaScript 内で HTML に似たコードを書くことができる）に似た構文を提供して、マークアップを作成します。\n\n### クラシック HTML への変換\n\n私たちのウェブサイトがどのように見えるかについての良いアイデアが既にあるので、単純にドラフトを `html!` と互換性のある表現に変換することができます。シンプルな HTML を書くことに慣れているなら、`html!` でマークアップを書くのに問題はないはずです。このマクロは HTML といくつかの違いがあることに注意してください：\n\n1. 式は中括弧（`{ }`）で囲む必要があります。\n2. ルートノードは1つだけでなければなりません。コンテナにラップせずに複数の要素を持ちたい場合は、空のタグ/フラグメント（`<> ... </>`）を使用できます。\n3. 要素は正しく閉じる必要があります。\n\nレイアウトを構築したいので、元の HTML は次のようになります：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nそれでは、この HTML を `html!` に変換しましょう。次のコードスニペットを `app` 関数の本体に入力（またはコピー/ペースト）して、関数が `html!` の値を返すようにします。\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\nブラウザページをリフレッシュすると、次の出力が表示されるはずです：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### マークアップ内でRustの構造を使用する\n\nRustでマークアップを書く大きな利点の1つは、マークアップ内でRustのすべての利点を享受できることです。\n今では、HTML内にビデオリストをハードコーディングするのではなく、それらを `Vec` の `Video` 構造体として定義します。\nデータを保持するために、`main.rs` または選択した任意のファイルにシンプルな `struct` を作成します。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n次に、この構造体のインスタンスを `app` 関数内で作成し、ハードコーディングされたデータの代わりにそれらを使用します：\n\n```rust\nuse website_test::tutorial::Video; // 自分のパスに置き換えてください\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\nそれらを表示するために、`Vec` を `Html` に変換する必要があります。これを実現するには、イテレータを作成し、それを `html!` にマッピングして `Html` として収集します：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\nリスト項目にキーを使用することで、Yew はリスト内のどの項目が変更されたかを追跡し、より高速な再レンダリングを実現できます。[リストには常にキーを使用することをお勧めします](/concepts/html/lists.mdx#keyed-lists)。\n::\n\n最後に、データから作成された `Html` を使用してハードコーディングされたビデオリストを置き換える必要があります：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## コンポーネント\n\nコンポーネントは Yew アプリケーションの構成要素です。コンポーネントを組み合わせることで（他のコンポーネントで構成されることもあります）、アプリケーションを構築します。再利用可能性を考慮してコンポーネントを構築し、それらを汎用的に保つことで、コードやロジックを繰り返すことなく、アプリケーションの複数の部分でそれらを使用できるようになります。\n\nこれまで使用してきた `app` 関数は `App` と呼ばれるコンポーネントであり、「関数コンポーネント」と呼ばれます。\n\n1. 構造体コンポーネント\n2. 関数コンポーネント\n\nこのチュートリアルでは、関数コンポーネントを使用します。\n\nでは、`App` コンポーネントをより小さなコンポーネントに分割しましょう。まず、ビデオリストを独自のコンポーネントに抽出します。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n`VideosList` 関数コンポーネントのパラメータに注意してください。関数コンポーネントは1つの引数しか受け取らず、その引数は \"props\"（\"properties\" の略）を定義します。Props は親コンポーネントから子コンポーネントにデータを渡すために使用されます。この場合、`VideosListProps` は props を定義する構造体です。\n\n:::important\nprops に使用される構造体は `Properties` を派生実装する必要があります。\n:::\n\n上記のコードをコンパイルするために、`Video` 構造体を次のように変更する必要があります：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n次に、`VideosList` コンポーネントを使用するように `App` コンポーネントを更新できます。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nブラウザウィンドウを確認することで、リストが期待通りにレンダリングされているかどうかを検証できます。リストのレンダリングロジックをそのコンポーネントに移動しました。これにより、`App` コンポーネントのソースコードが短くなり、読みやすく理解しやすくなりました。\n\n### アプリケーションをインタラクティブにする\n\nここでの最終目標は、選択したビデオを表示することです。そのためには、`VideosList` コンポーネントがビデオを選択したときに親コンポーネントに「通知」する必要があります。これは `Callback` を使用して行います。この概念は「ハンドラの伝播」と呼ばれます。props を変更して `on_click` コールバックを受け取るようにします：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n次に、選択したビデオをコールバックに渡すように `VideosList` コンポーネントを変更します。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n次に、`VideosList` の使用を変更してそのコールバックを渡す必要があります。しかし、その前に、新しいコンポーネント `VideoDetails` を作成し、ビデオがクリックされたときに表示されるようにします。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n次に、`App` コンポーネントを変更して、ビデオが選択されたときに `VideoDetails` コンポーネントを表示するようにします。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n今は `use_state` について心配する必要はありません。後でこの問題に戻ります。リストデータを `{ for details }` で抽出するテクニックに注目してください。\n`Option<_>` は `Iterator` を実装しているので、特殊な `{ for ... }` 構文を使用して `Iterator` が返す唯一の要素を順番に表示することができます。これは [`html!` マクロ](concepts/html/lists) によってサポートされています。\n\n### 状態の処理\n\n以前に使用した `use_state` を覚えていますか？それは \"フック\" と呼ばれる特殊な関数です。フックは関数コンポーネントのライフサイクルに \"フック\" して操作を実行するために使用されます。このフックや他のフックについては[こちら](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)で詳しく学ぶことができます。\n\n:::note\n構造体コンポーネントは異なる動作をします。これらについては[ドキュメント](advanced-topics/struct-components/introduction.mdx)を参照してください。\n:::\n\n## データの取得（外部 REST API の使用）\n\n実際のアプリケーションでは、データは通常ハードコーディングされているのではなく、API から取得されます。外部ソースからビデオリストを取得してみましょう。そのためには、以下のクレートを追加する必要があります：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  fetch 呼び出しを行うために使用します。\n- [`serde`](https://serde.rs) とその派生特性\n  JSON 応答をデシリアライズするために使用します。\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  Rust の Future を Promise として実行するために使用します。\n\n`Cargo.toml` ファイルの依存関係を更新しましょう：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n依存関係を選択する際には、それらが `wasm32` と互換性があることを確認してください！そうでない場合、アプリケーションを実行することはできません。\n:::\n\n`Deserialize` 特性を派生するように `Video` 構造体を更新します：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n最後のステップとして、ハードコーディングされたデータを使用するのではなく、fetch リクエストを行うように `App` コンポーネントを更新する必要があります。\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\nここでは `unwrap` を使用していますが、これはデモアプリケーションのためです。実際のアプリケーションでは、[適切なエラーハンドリング](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)を行うことをお勧めします。\n:::\n\nさて、ブラウザを確認して、すべてが期待通りに動作しているかを確認しましょう……CORS の問題がなければ。これを解決するために、プロキシサーバーが必要です。幸いなことに、trunk はこの機能を提供しています。\n\nこれらの行を更新します：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n次に、以下のコマンドを使用してサーバーを再起動します：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nページをリフレッシュすると、すべてが期待通りに動作するはずです。\n\n## まとめ\n\nおめでとうございます！外部 API からデータを取得し、ビデオリストを表示する Web アプリケーションを作成しました。\n\n## 次に\n\nこのアプリケーションは、完璧または有用になるまでにはまだ長い道のりがあります。このチュートリアルを完了した後、より高度なトピックを探求するための出発点として使用できます。\n\n### スタイル\n\n私たちのアプリケーションは非常に見栄えが悪いです。CSS やその他のスタイルがありません。残念ながら、Yew は組み込みのスタイルコンポーネントを提供していません。スタイルシートを追加する方法については、[Trunk のアセット](https://trunkrs.dev/assets/)を参照してください。\n\n### さらなる依存ライブラリ\n\n私たちのアプリケーションは、非常に少ない外部依存関係を使用しています。使用できる多くのクレートがあります。詳細については、[外部ライブラリ](/community/external-libs)を参照してください。\n\n### Yew についてもっと知る\n\n私たちの[公式ドキュメント](../getting-started/introduction.mdx)を読んでください。多くの概念についてより詳細に説明しています。Yew API についてもっと知りたい場合は、[API ドキュメント](https://docs.rs/yew)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/current.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Function Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Intro With Basic Web Technologies\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew mostly operates on the idea of keeping everything that a reusable piece of UI may need, in one place - rust files. But also seeks to stay close to the original look of the technology. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: How it works\ndescription: Low level details about the framework\n---\n\n# 低レベルなライブラリの中身\n\nコンポーネントのライフサイクルの状態機械、VDOM の異なるアルゴリズム\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: Optimizations\ndescription: Make your app faster\n---\n\n# 最適化とベストプラクティス\n\n## neq_assign\n\n親コンポーネントから props を受け取った際、`change`メソッドが呼ばれます。\nこれはコンポーネントの状態を更新することができるのに加え、コンポーネントが props が変わった際に再レンダリングするかどうかを決める\n`ShouldRender`という真偽値を返すことができます。\n\n再レンダリングはコストがかかるもので、もし避けられるのであれば避けるべきです。\n一般的なルールとして props が実際に変化した際にのみ再レンダリングすれば良いでしょう。\n以下のコードブロックはこのルールを表しており、props が前と変わったときに`true`を返します。\n\n```rust\nuse yew::ShouldRender;\n\n#[derive(PartialEq)]\nstruct ExampleProps;\n\nstruct Example {\n    props: ExampleProps,\n};\n\nimpl Example {\n    fn change(&mut self, props: ExampleProps) -> ShouldRender {\n        if self.props != props {\n            self.props = props;\n            true\n        } else {\n            false\n        }\n    }\n}\n```\n\nしかし我々は先に進んでいけます！\nこの 6 行のボイラープレードは`PartialEq`を実装したものにトレイトとブランケットを用いることで 1 行のコードへと落とし込むことができます。\n[こちら](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html)にて`yewtil`クレートの`NewAssign`トレイトを見てみてください。\n\n## 効果的にスマートポインタを使う\n\n**注意: このセクションで使われている用語がわからなければ Rust book は\n[スマートポインタについての章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\nがあり、非常に有用です。**\n\n再レンダリングの際に props を作るデータを大量にコピーしないために、スマートポインタを用いてデータ自体ではなくデータへの参照だけを\nコピーできます。\nprops や子コンポーネントで関連するデータに実データではなく参照を渡すと、子コンポーネントでデータを変更する必要がなければ\nデータのコピーを避けることができます。\nその際、`Rc::make_mut`によって変更したいデータの変更可能な参照を得ることができます。\n\nこれにより、props が変更されたときにコンポーネントが再レンダリングされるかどうかを決めるかで`Component::change`に更なる恩恵があります。\nなぜなら、データの値を比較する代わりに元々のポインタのアドレス (つまりデータが保管されている機械のメモリの場所) を比較できるためです。\n2 つのポインターが同じデータを指す場合、それらのデータの値は同じでなければならないのです。\nただし、その逆は必ずしも成り立たないことに注意してください!\nもし 2 つのポインタが異なるのであれば、そのデータは同じである可能性があります。\nこの場合はデータを比較するべきでしょう。\n\nこの比較においては`PartialEq`ではなく`Rc::ptr_eq`を使う必要があります。\n`PartialEq`は等価演算子`==`を使う際に自動的に使われます。\nRust のドキュメントには[`Rc::ptr_eq`についてより詳しく書いてあります](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\nこの最適化は`Copy`を実装していないデータの型に対して極めて有効なものです。\nもしデータを簡単に変更できるのであれば、スマートポインタに取り換える必要はありません。\nしかし`Vec`や`HashMap`、`String`などのような重たいデータの構造体に対してはスマートポインタを使うことで\nパフォーマンスを改善することができるでしょう。\n\nこの最適化は値がまだ一度も子によって更新されていない場合に極めて有効で、親からほとんど更新されない場合においてもかなり有効です。\nこれにより、`Rc<_>s`が純粋なコンポーネントに対してプロパティの値をラップする良い一手となります。\n\n## View 関数\n\nコードの可読性の理由から`html!`の部分を関数へと移植するのは意味があります。\nこれは、インデントを減らすのでコードを読みやすくするだけでなく、良いデザインパターンを産むことにも繋がるのです。\nこれらの関数は複数箇所で呼ばれて書くべきコード量を減らせるため、分解可能なアプリケーションを作ることができるのです。\n\n## 純粋なコンポーネント\n\n純粋なコンポーネントは状態を変化せず、ただ中身を表示してメッセージを普通の変更可能なコンポーネントへ渡すコンポーネントのことです。\nView 関数との違いとして、純粋なコンポーネントは式の構文\\(`{some_view_function()}`\\)ではなく\nコンポーネントの構文\\(`<SomePureComponent />`\\)を使うことで`html!`マクロの中で呼ばれる点、\nそして実装次第で記憶され (つまり、一度関数が呼ばれれば値は\"保存\"され、\n同じ引数でもう一度呼ばれても値を再計算する必要がなく最初に関数が呼ばれたときの保存された値を返すことができる)、\n先述の`neq_assign`ロジックを使う別々の props で再レンダリングを避けられる点があります。\n\nYew は純粋な関数やコンポーネントをサポートしていませんが、外部のクレートを用いることで実現できます。\n\n## 関数型コンポーネント (a.k.a フック)\n\n関数型コンポーネントはまだ開発中です！\n開発状況については[プロジェクトボード](https://github.com/yewstack/yew/projects/3)に詳しく書いてあります。\n\n## キー付き DOM ノード\n\n## ワークスペースでコンパイル時間を減らす\n\n間違いなく Yew を使う上での最大の欠点はコンパイルに時間がかかる点です。\nプロジェクトのコンパイルにかかる時間は`html!`マクロに渡されるコードの量に関係しています。\nこれは小さなプロジェクトにはそこまで問題ないようですが、大きなアプリではコードを複数クレートに分割することでアプリに変更が加られた際に\nコンパイラの作業量を減らすのが有効です。\n\n一つ可能なやり方として、ルーティングとページ洗濯を担当するメインのクレートを作り、それぞれのページに対して別のクレートを作ることです。\nそうして各ページは異なるコンポーネントか、`Html`を生成する大きな関数となります。\nアプリの異なる部分を含むクレート同士で共有されるコードはプロジェクト全体で依存する分離したクレートに保存されます。\n理想的には 1 回のコンパイルでコード全てを再ビルドせずメインのクレートかどれかのページのクレートを再ビルドするだけにすることです。\n最悪なのは、\"共通\"のクレートを編集して、はじめに戻ってくることです:\n共有のクレートに依存している全てのコード、恐らく全てのコードをコンパイルすることです。\n\nもしメインのクレートが重たすぎる、もしくは深くネストしたページ (例えば別ページのトップでレンダリングされるページ)\nで速く繰り返したい場合、クレートの例を用いてメインページの実装をシンプルにしたりトップで動かしているコンポーネントをレンダリングできます。\n\n## バイナリサイズを小さくする\n\n- Rust のコードを最適化する\n- `cargo.toml` \\( release profile を定義 \\)\n- `wasm-opt`を用いて wasm のコードを最適化する\n\n**注意: バイナリサイズを小さくするのについては[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)に詳しく書いてあります。**\n\n### Cargo.toml\n\n`Cargo.toml`で`[profile.release]`のセクションに設定を書き込むことでリリースビルドを小さくすることが可能です。\n\n```text\n[profile.release]\n# バイナリに含むコードを少なくする\npanic = 'abort'\n# コードベース全体での最適化 ( 良い最適化だがビルドが遅くなる)\ncodegen-units = 1\n# サイズの最適化( よりアグレッシブに )\nopt-level = 'z'\n# サイズの最適化\n# opt-level = 's'\n# プログラム全体の分析によるリンク時最適化\nlto = true\n```\n\n### wasm-opt\n\n更に`wasm`のコードのサイズを最適化することができます。\n\nThe Rust Wasm Book には Wasm バイナリのサイズを小さくすることについてのセクションがあります:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- `wasm-pack`でデフォルトの`wasm`のコードをリリースビルド時に最適化する\n- `wasm-opt`によって直接`wasm`ファイルを最適化する\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### yew/examples/にある例を小さなサイズでビルドする\n\n注意: `wasm-pack`は Rust と Wasm のコードへの最適化を組み合わせます。`wasm-bindgen`はこの例では Rust のサイズ最適化を用いていません。\n\n| 使用したツール              | サイズ |\n| :-------------------------- | :----- |\n| wasm-bindgen                | 158KB  |\n| wasm-bindgen + wasm-opt -Os | 116KB  |\n| wasm-pack                   | 99 KB  |\n\n## 参考文献:\n\n- [The Rust Book のスマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [the Rust Wasm Book でのバイナリサイズを小さくすることについて](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust profiles についてのドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: Callbacks\ndescription: ComponentLink and Callbacks\n---\n\n”リンク”コンポーネントはコンポーネントがコールバックを登録できて自身を更新することができるメカニズムです。\n\n## ComponentLink API\n\n### callback\n\n実行時にコンポーネントの更新メカニズムにメッセージを送信するコールバックを登録します。\nこれは、渡されたクロージャから返されるメッセージで `send_self` を呼び出します。\n`Fn(IN) -> Vec<COMP::Message>`が渡され、`Callback<IN>`が返されます。\n\n### send_message\n\n現在のループが終了した直後にコンポーネントにメッセージを送信し、別の更新ループを開始します。\n\n### send_message_batch\n\n実行時に一度に多数のメッセージを一括して送信するコールバックを登録します。\nメッセージによってコンポーネントが再レンダリングされる場合、バッチ内のすべてのメッセージが処理された後、コンポーネントは再レンダリングされます。\n`Fn(IN) -> COMP::Message`が渡され、`Callback<IN>`が返されます。\n\n## コールバック\n\n_\\(This might need its own short page.\\)_\n\nコールバックは、Yew 内のサービス、エージェント、親コンポーネントとの通信に使われます。\nこれらは単に `Fn` を `Rc` でラップしただけであり、クローンを作成できるようにするためのものです。\n\nこれらの関数には `emit` 関数があり、`<IN>` 型を引数に取り、それをアドレスが欲しいメッセージに変換します。\n親からのコールバックが子コンポーネントに props で提供されている場合、子は `update` ライフサイクルフックで `emit` をコールバックに呼び出して親にメッセージを返すことができます。\nマクロ内で props として提供されたクロージャや関数は自動的にコールバックに変換されます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: Introduction\ndescription: Components and their lifecycle hooks\n---\n\n## コンポーネントとは?\n\nコンポーネントは Yew を構成するブロックです。\nコンポーネントは状態を管理し、自身を DOM へレンダリングすることができます。\nコンポーネントはライフサイクルの機能がある`Component`トレイトを実装することによって作られます。\n\n## ライフサイクル\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/docs/issues/22)\n:::\n\n## ライフサイクルのメソッド\n\n### Create\n\nコンポーネントが作られると、`ComponentLink`と同様に親コンポーネントからプロパティを受け取ります。\nプロパティはコンポーネントの状態を初期化するのに使われ、\"link\"はコールバックを登録したりコンポーネントにメッセージを送るのに使われます。\n\nprops と link をコンポーネント構造体に格納するのが一般的です。\n例えば:\n\n```rust\npub struct MyComponent {\n    props: Props,\n    link: ComponentLink<Self>,\n}\n\nimpl Component for MyComponent {\n    type Properties = Props;\n    // ...\n\n    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { props, link }\n    }\n\n    // ...\n}\n```\n\n### View\n\nコンポーネントは`view()`メソッドによってレイアウトを宣言します。\nYew は`html!`マクロによって HTML と SVG ノード、リスナー、子コンポーネントを宣言できます。\nマクロは React の JSX のような動きをしますが、JavaScript の代わりに Rust の式を用います。\n\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        let onclick = self.link.callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ self.props.button_text }</button>\n        }\n    }\n}\n```\n\n使い方については[`html!`ガイド](concepts/html/introduction.mdx)をご確認ください。\n\n### Rendered\n\n`rendered()`コンポーネントのライフサイクルのメソッドは`view()`が処理されたて Yew がコンポーネントをレンダリングした後、\nブラウザがページを更新する前に呼ばれます。\nコンポーネントは、コンポーネントが要素をレンダリングした後にのみ実行できるアクションを実行するため、このメソッドを実装したい場合があります。\nコンポーネントが初めてレンダリングされたかどうかは `first_render` パラメータで確認できます。\n\n```rust\nuse stdweb::web::html_element::InputElement;\nuse stdweb::web::IHtmlElement;\nuse yew::prelude::*;\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    fn rendered(&mut self, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.try_into::<InputElement>() {\n                input.focus();\n            }\n        }\n    }\n}\n```\n\n:::tip note\nライフサイクルメソッドは実装の必要がなく、デフォルトでは何もしません。\n:::\n\n### Update\n\nコンポーネントは動的で、非同期メッセージを受信するために登録することができます。\nライフサイクルメソッド `update()` はメッセージごとに呼び出されます。\nこれにより、コンポーネントはメッセージが何であったかに基づいて自身を更新し、自身を再レンダリングする必要があるかどうかを判断することができます。\nメッセージは、HTML 要素リスナーによってトリガーされたり、子コンポーネント、エージェント、サービス、または Futures によって送信されたりします。\n\n`update()`がどのようなのかについての例は以下の通りです:\n\n```rust\npub enum Msg {\n    SetInputEnabled(bool)\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n\n    // ...\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n       match msg {\n           Msg::SetInputEnabled(enabled) => {\n               if self.input_enabled != enabled {\n                   self.input_enabled = enabled;\n                   true // Re-render\n               } else {\n                   false\n               }\n           }\n       }\n    }\n}\n```\n\n### Change\n\nコンポーネントは親によって再レンダリングされることがあります。\nこのような場合、新しいプロパティを受け取り、再レンダリングを選択する可能性があります。\nこの設計では、プロパティを変更することで、親から子へのコンポーネントの通信が容易になります。\n\n典型的な実装例は以下の通りです:\n\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn change(&mut self, props: Self::Properties) -> ShouldRender {\n        if self.props != props {\n            self.props = props;\n            true\n        } else {\n            false\n        }\n    }\n}\n```\n\n### Destroy\n\nコンポーネントが DOM からアンマウントされた後、Yew は `destroy()` ライフサイクルメソッドを呼び出し、必要なクリーンアップ操作をサポートします。\nこのメソッドはオプションで、デフォルトでは何もしません。\n\n## Associated Types\n\n`Component`トレイトは 2 つの関連型があります: `Message`と`Properties`です。\n\n```rust\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message`はコンポーネントによって処理され、何らかの副作用を引き起こすことができるさまざまなメッセージを表します。\n例えば、API リクエストをトリガーしたり、UI コンポーネントの外観を切り替えたりする `Click` メッセージがあります。\nコンポーネントのモジュールで `Msg` という名前の列挙型を作成し、それをコンポーネントのメッセージ型として使用するのが一般的です。\n\"message\"を\"msg\"と省略するのも一般的です。\n\n```rust\nenum Msg {\n    Click,\n}\n```\n\n`Properties`は、親からコンポーネントに渡される情報を表します。\nこの型は Properties trait を実装していなければならず\\(通常はこれを派生させることで\\)、特定のプロパティが必須かオプションかを指定することができます。\nこの型は、コンポーネントの作成・更新時に使用されます。\nコンポーネントのモジュール内に `Props` という構造体を作成し、それをコンポーネントの `Properties` 型として使用するのが一般的です。\n”Properties”を\"props\"に短縮するのが一般的です。\nProps は親コンポーネントから継承されるので、アプリケーションのルートコンポーネントは通常`()`型の`Properties`を持ちます。\nルートコンポーネントのプロパティを指定したい場合は、`App::mount_with_props`メソッドを利用します。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: Properties\ndescription: Parent to child communication\n---\n\nプロパティは、子コンポーネントと親コンポーネントが互いに通信できるようにします。\n\n## マクロの継承\n\n`Properties`を自分で実装しようとせず、代わりに`#[derive(Properties)]`を使ってください。\n\n:::note\n`Properties`を継承した型は`Clone`を実装していなければいけません。\nこれは`#[derive(Properties, Clone)`か`Clone`を手で実装することで可能です。\n:::\n\n### 必要な属性\n\nデフォルトでは、`Properties` を導出する構造体内のフィールドは必須です。\nフィールドが欠落していて `html!` マクロでコンポーネントが作成された場合、コンパイラエラーが返されます。\nオプションのプロパティを持つフィールドについては、`#[prop_or_default]` 属性を使用して、prop が指定されていない場合はその型のデフォルト値を使用します。\n値を指定するには `#[prop_or(value)]` 属性を用います。\nここで value はプロパティのデフォルト値、あるいは代わりに `#[prop_or_else(function)]` を使用して、`function` はデフォルト値を返します。\n例えば、ブール値のデフォルトを `true` とするには、属性 `#[prop_or(true)]` を使用します。オプションのプロパティでは、デフォルト値 `None` を持つ `Option` 列挙型を使うのが一般的です。\n\n### PartialEq\n\nもし可能なら props で `PartialEq` を継承するのが良いかもしれません。\n`PartialEq`を使うことで、不必要な再レンダリングを避けることができます\n(これについては、**最適化とベストプラクティス**のセクションで説明しています)。\n\n## プロパティを使用する際のメモリと速度のオーバーヘッド\n\n`Component::view`ではコンポーネントの状態への参照を取り、それを使って `Html` を作成します。\nしかし、プロパティは自身の値です。\nつまり、それらを作成して子コンポーネントに渡すためには、`view` 関数で提供される参照を所有する必要があるのです。\nこれは所有する値を取得するためにコンポーネントに渡される参照を暗黙のうちにクローンすることで行われます。\n\nこれは、各コンポーネントが親から受け継いだ状態の独自のコピーを持っていることを意味し、コンポーネントを再レンダリングするときはいつでも、再レンダリングしたコンポーネントのすべての子コンポーネントの props がクローンされなければならないことを意味します。\n\nこのことの意味するところは、もしそうでなければ*大量の*データ \\(10KB もあるような文字列\\) を props として渡してしまうのであれば、子コンポーネントを親が呼び出す `Html` を返す関数にすることを考えた方がいいかもしれないということです。\n\nprops を介して渡されたデータを変更する必要がない場合は、実際のデータそのものではなく、データへの参照カウントされたポインタのみが複製されるように `Rc` でラップすることができます。\n\n## 例\n\n```rust\nuse std::rc::Rc;\nuse yew::Properties;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nimpl Default for LinkColor {\n    fn default() -> Self {\n        // The link color will be blue unless otherwise specified.\n        LinkColor::Blue\n    }\n}\n\n#[derive(Properties, Clone, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: String,\n    /// If the link text is huge, this will make copying the string much cheaper.\n    /// This isn't usually recommended unless performance is known to be a problem.\n    text: Rc<String>,\n    /// Color of the link.\n    #[prop_or_default]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: Refs\ndescription: Out-of-band DOM access\n---\n\n`ref`は、任意の HTML 要素やコンポーネントの内部で、割り当てられている DOM`Element`を取得するために使用することができます。\nこれは、`view` ライフサイクルメソッドの外で DOM に変更を加えるために使用できます。\n\nこれは、キャンバスの要素を取得したり、ページの異なるセクションにスクロールしたりするのに便利です。\n\n構文は以下の通りです:\n\n```rust\n// In create\nself.node_ref = NodeRef::default();\n\n// In view\nhtml! {\n    <div ref={self.node_ref.clone()}></div>\n}\n\n// In update\nlet has_attributes = self.node_ref.try_into::<Element>().has_attributes();\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/agents.mdx",
    "content": "---\ntitle: Agents\ndescription: Yew's Actor System\n---\n\nエージェントは Angular の[サービス](https://angular.io/guide/architecture-services)に似ており\\(ただし依存性インジェクションはありません\\)、\n[アクターモデル](https://en.wikipedia.org/wiki/Actor_model)を提供します。\nエージェントはコンポーネント階層のどこに位置するかに関わらず、コンポーネント間でメッセージをルーティングしたり、共有状態を作成したり、UI をレンダリングするメインスレッドから計算量の多いタスクをオフロードするために使用することができます。\nまた、Yew アプリケーションがタブをまたいで通信できるようにするためのエージェントのサポートも\\(将来的には\\)計画されています。\n\nエージェントが並行に動くように Yew は[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)を使用しています。\n\n## ライフサイクル\n\n![エージェントのライフサイクル](https://user-images.githubusercontent.com/42674621/79125224-b6481d80-7d95-11ea-8e6a-ab9b52d1d8ac.png)\n\n## エージェントの種類\n\n### Reaches\n\n- Context - Context エージェントのインスタンスは、常に最大 1 つ存在します。\n  Bridges は、UI スレッド上で既にスポーンされたエージェントをスポーンするか、接続します。\n  これは、コンポーネントまたは他のエージェント間の状態を調整するために使用することができます。\n  このエージェントに Bridges が接続されていない場合、このエージェントは消滅します。\n\n- Job - 新しいブリッジごとに UI スレッド上で新しいエージェントをスポーンします。\n  これは、ブラウザと通信する共有されているが独立した動作をコンポーネントの外に移動させるのに適しています。\n  (TODO 確認) タスクが完了すると、エージェントは消えます。\n\n- Public - Context と同じですが、独自の web worker で動作します。\n\n- Private - Job と同じですが、独自の web worker で動作します。\n\n- Global \\(WIP\\)\n\n## エージェントとコンポーネントのやり取り\n\n### Bridges\n\nBridge は、エージェントとコンポーネント間の双方向通信を可能にします。\nまた、Bridge はエージェント同士の通信を可能にします。\n\n### Dispatchers\n\nDispatcher は、コンポーネントとエージェント間の一方向通信を可能にします。\nDispatcher は、コンポーネントがエージェントにメッセージを送信することを可能にします。\n\n## オーバーヘッド\n\n独自の独立した web worker(プライベートとパブリック)にあるエージェントは、送受信するメッセージにシリアライズするオーバーヘッドが発生します。\n他のスレッドとの通信には[bincode](https://github.com/servo/bincode)を使用するので、関数を呼び出すよりもコストはかなり高くなります。\n計算コストがメッセージの受け渡しコストを上回る場合を除き、ロジックを UI スレッドエージェント\\(Job または Context\\)に格納する必要があります。\n\n## 参考資料\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib)の例でコンポーネントがどのようにエージェントと通信させているかがわかります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/html/components.mdx",
    "content": "---\ntitle: Components\ndescription: Create complex layouts with component hierarchies\n---\n\n## 基本\n\n`Component`を実装しているあらゆる型は`html!`マクロの中で使えます:\n\n```rust\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponent prop1=\"lorem\" prop2=\"ipsum\" />\n\n        // With the whole set of props provided at once\n        <MyComponent ..props />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponent prop2=\"lorem\" ..props />\n    </>\n}\n```\n\n## ネスト\n\n`children`フィールドが`Properties`の中にある場合はコンポーネントは子に渡されます。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <Container>\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n}\n```\n\n```rust title=\"container.rs\"\npub struct Container(Props);\n\n#[derive(Properties, Clone)]\npub struct Props {\n    pub children: Children,\n}\n\nimpl Component for Container {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n       html! {\n           <div id=\"container\">\n               { self.0.children.clone() }\n           </div>\n       }\n    }\n}\n```\n\n:::note\n`Properties`を継承した型は`Clone`を実装していなければいけません。\nこれは`#[derive(Properties, Clone)]`を使うか手で`Clone`を実装すれば良いです。\n:::\n\n## Props とネストした子コンポーネント\n\nネストしたコンポーネントのプロパティは格納しているコンポーネントの型が子である場合はアクセス可能、または変更可能です。\n以下の例では`List`コンポーネントは`ListItem`コンポーネントをラップできています。\n実際の使用においてこのパターンの例については`yew-router`のソースコードを確認してみてください。\nより進んだ例としては Yew のメインのリポジトリにある`nested-list`を確認してみてください。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n}\n```\n\n```rust title=\"list.rs\"\npub struct List(Props);\n\n#[derive(Properties, Clone)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\nimpl Component for List {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n        html!{{\n            for self.0.children.iter().map(|mut item| {\n                item.props.value = format!(\"item-{}\", item.props.value);\n                item\n            })\n        }}\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/html/elements.mdx",
    "content": "---\ntitle: Elements\ndescription: Both HTML and SVG elements are supported\n---\n\n## タグ構造\n\n要素のタグは`<... />`のような自己完結タグか、開始タグに対応した終了タグを持っている必要があります。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Open - Close-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"></div>\n}\n```\n\n<!--Invalid-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n}\n```\n\n<!--Self-closing-->\n\n```rust\nhtml! {\n  <input id=\"my_input\" />\n}\n```\n\n<!--Invalid-->\n\n```rust\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n:::note\n便利さのために、*普通は*終了タグを必要とする要素は自己完結タグとすることが**できます**。\n例えば`html! { <div class=\"placeholder\" /> }`と書くのは有効です。\n:::\n\n## 子\n\n複雑にネストした HTML や SVG のレイアウトを書くのには以下のようにするのが楽です:\n\\*\\*\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--HTML-->\n\n```rust\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n}\n```\n\n<!--SVG-->\n\n```rust\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <feGaussianBlur stdDeviation=\"2\"/>\n                <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## クラス\n\n要素へのクラスを特定する便利なやり方はたくさんあります:\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Literal-->\n\n```rust\nhtml! {\n  <div class=\"container\"></div>\n}\n```\n\n<!--Multiple-->\n\n```rust\nhtml! {\n  <div class=\"container center-align\"></div>\n}\n```\n\n<!--Interpolated-->\n\n```rust\nhtml! {\n  <div class={format!(\"{}-container\", size)}></div>\n}\n```\n\n<!--Expression-->\n\n```rust\nhtml! {\n  <div class={self.classes()}></div>\n}\n```\n\n<!--Tuple-->\n\n```rust\nhtml! {\n  <div class={(\"class-1\", \"class-2\")}></div>\n}\n```\n\n<!--Vector-->\n\n```rust\nhtml! {\n  <div class={vec![\"class-1\", \"class-2\"]}></div>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## リスナー\n\nリスナー属性はクロージャのラッパーである`Callback`に渡される必要があります。\nコールバックをどのように作るかはアプリをリスナーイベントにどう反応させたいかによります。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Component handler-->\n\n```rust\nstruct MyComponent {\n    link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => {\n                // Handle Click\n            }\n        }\n    }\n\n    fn view(&self) -> Html {\n        // Create a callback from a component link to handle it in a component\n        let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Agent Handler-->\n\n```rust\nstruct MyComponent {\n    worker: Dispatcher<MyWorker>,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent {\n            worker: MyWorker::dispatcher()\n        }\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // Create a callback from a worker to handle it in another context\n        let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Other Cases-->\n\n```rust\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // Create an ephemeral callback\n        let click_callback = Callback::from(|| {\n            ConsoleService::log(\"clicked!\");\n        });\n\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## イベントの型\n\n:::note\n以下のテーブルにある全てのイベントの型は`yew::events`で再エクスポートされています。\nAll the event types mentioned in the following table are re-exported under `yew::events`. Using the types from\n`yew::events` makes it easier to ensure version compatibility than if you were to manually include `web-sys`\nor `stdweb` as dependencies in your crate because you won't end up using a version which conflicts with\nthe version Yew specifies.\n:::\n\n| イベント名                  | `web_sys` イベント型                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [ChangeData](https://docs.rs/yew/latest/yew/events/enum.ChangeData.html)              |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.htmk)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputData](https://docs.rs/yew/latest/yew/events/struct.InputData.html)              |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/html/introduction.mdx",
    "content": "---\ntitle: Introduction\ndescription: The procedural macro for generating HTML and SVG\nslug: /concepts/html\n---\n\n`html!`マクロによって HTML と SVG のコードを宣言的に書くことができます。\nJSX \\(HTML のようなコードを JavaScript 内部に書くことができる JavaScript の拡張\\) に似ています。\n\n**重要な注意**\n\n1. `html!`マクロはルートの HTML ノードのみ受け付けます \\([フラグメントかイテレータを使う](./lists.mdx)ことでやり取りできます\\)\n2. 空の`html! {}`の呼び出しは可能ですが何もレンダリングしません\n3. リテラルはクオーテーションがつけられ、ブレースで囲う必要があります: `html! { \"Hello, World\" }`\n\n:::note\n`html!`マクロはコンパイラのデフォルトの再帰の上限に簡単に達してしまいます。\nもしコンパイラエラーに遭遇した場合はその値を押し出すといいかもしれません。\nクレートのルート\\(つまり、`lib.rs`か`main.rs`\\)で`#![recursion_limit=\"1024\"]`のような属性を使えば解決します。\n\n詳しくは[公式ドキュメント](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)と[Stack Overflow の質問](https://stackoverflow.com/questions/27454761/what-is-a-crate-attribute-and-where-do-i-add-it)を見てみてください。\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/html/lists.mdx",
    "content": "---\ntitle: Lists\n---\n\n## フラグメント\n\n`html!`マクロは常にルートノードが 1 つであることを要求します。\nこの制限のために、空のタグを使って内容をラップすると良いでしょう。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Valid-->\n\n```rust\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n}\n```\n\n<!--Invalid-->\n\n```rust\n/* error: only one root html element allowed */\n\nhtml! {\n    <div></div>\n    <p></p>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## イテレータ\n\nYew はイテレータから HTML をビルドするのに 2 つの方法をサポートしています。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Syntax Type 1-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { self.props.items.iter().map(renderItem).collect::<Html>() }\n    </ul>\n}\n```\n\n<!--Syntax Type 2-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { for self.props.items.iter().map(renderItem) }\n    </ul>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: Literals and Expressions\n---\n\n## リテラル\n\n式が`Display`を実装した型を解決する場合、文字列に変換されて DOM に[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text)ノードとして挿入されます。\n\nテキストは式として処理されるため、全ての表示される内容は`{}`ブロックによって囲まれる必要があります。\nこれは Yew のアプリと通常の HTML の構文で最も異なる点です。\n\n```rust\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n}\n```\n\n## 式\n\nHTML に`{}`ブロックを使って式を挿入することができます。\n\n```rust\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n}\n```\n\n式を関数やクロージャに分離するのはコードの可読性の観点から有効なことがあります。\n\n```rust\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/concepts/router.mdx",
    "content": "---\ntitle: Router\ndescription: Yew's official router\n---\n\n[crates.io にあるルータ](https://crates.io/crates/yew-router)\n\nシングルページアプリケーション\\(SPA\\)におけるルータは URL よってページを出し分けます。\nリンクがクリックされたときに異なるリソースを要求するというデフォルトの動作の代わりに、ルータはアプリケーション内の有効なルートを指すように URL をローカルに設定します。\nルータはこの変更を検出してから、何をレンダリングするかを決定します。\n\n## コアとなる要素\n\n### `Route`\n\nURL 内のドメインの後のすべてを表す文字列と、オプションで history API に保存されている状態を含みます。\n\n### `RouteService`\n\nブラウザとやりとりしてルーティングを決めます。\n\n### `RouteAgent`\n\nRouteService を所有し、ルートが変更された際の更新を調整するために使用します。\n\n### `Switch`\n\n`Switch`トレイトは`Route`をトレイトの実装する側の間で変換するために用いられます。\n\n### `Router`\n\nRouter コンポーネントは RouteAgent とやり取りし、エージェントがどうスイッチするか Routes を自動的に解決します。\nこれは、結果として得られるスイッチがどのように Html に変換されるかを指定できるようにするため、props を介して公開されます。\n\n## ルータをどのように使うか\n\nまず、アプリケーションのすべての状態を表す型を作成します。\nこれは通常は列挙型ですが、構造体もサポートされており、`Switch` を実装した他のアイテムを内部に入れ子にすることができることに注意してください。\n\n次に、`Switch`を型に継承させなければいけません。\n列挙型の場合は全ての variant は`#[to = \"/some/route\"]`とアノテーションされている必要があり、代わり構造体を用いている場合は構造体宣言が外部から見えるようにしてなければいけません。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n  #[to=\"/\"]\n  Home\n}\n```\n\n:::caution\n`Switch`用の派生マクロによって生成された実装は、各 variant を最初から最後までの順にマッチさせようとするので、指定した`to`アノテーションのうち 2 つのルートにマッチする可能性がある場合は、最初のルートがマッチし、2 つ目のルートは試行されないことに注意してください。例えば、以下の`Switch`を定義した場合、マッチするルートは`AppRoute::Home`だけになります。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/\"]\n  Home,\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n}\n```\n\n:::\n\nまた、`#[to = \"\"]`アノテーションの中で`{}`のバリエーションを使ってセクションをキャプチャすることもできます。\n`{}`は、次の区切り文字\\(コンテキストに応じて \"/\", \"?\", \"&\", \"#\" のいずれか\\) までのテキストをキャプチャします。\n`{*}`は、次の文字が一致するまでテキストをキャプチャすることを意味します。\n`{<number>}`は、指定した数の区切り文字が見つかるまでテキストをキャプチャすることを意味します\n\\(例: `{2}`は区切り文字が 2 つ見つかるまでキャプチャします\\)。\n\n名前付きフィールドを持つ構造体や列挙型の場合は、キャプチャグループ内で以下のようにフィールドの名前を指定する必要があります。\n`{user_name}` または `{*:age}` のように、キャプチャグループ内でフィールドの名前を指定しなければなりません。\n\nSwitch トレイトは文字列よりも構造化されたキャプチャグループで動作します。\n`Switch`を実装した任意の型を指定することができます。\nそのため、キャプチャグループが `usize` であることを指定することができ、URL のキャプチャ部分がそれに変換できない場合、variant はマッチしません。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: Build a sample app\n---\n\nはじめに、Rust の新規ライブラリを作りましょう(**重要:** `--lib`フラグを渡すことで*バイナリ*ではなく*ライブラリ*を作ってください)\n\n```bash\ncargo new --lib yew-app && cd yew-app\n```\n\n依存ライブラリに`yew`と`wasm-bindgen`を追加してください \\(最新バージョンについては[こちら](https://docs.rs/yew)を参照してください\\)\n\n```toml title=\"Cargo.toml\"\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nauthors = [\"Yew App Developer <name@example.com>\"]\nedition = \"2018\"\n\n[lib]\ncrate-type = [\"cdylib\", \"rlib\"]\n\n[dependencies]\nyew = \"0.17\"\nwasm-bindgen = \"0.2\"\n```\n\n以下のテンプレートを `src/lib.rs`ファイルにコピーしてください:\n\n```rust title=\"src/lib.rs\"\nuse wasm_bindgen::prelude::*;\nuse yew::prelude::*;\n\nstruct Model {\n    link: ComponentLink<Self>,\n    value: i64,\n}\n\nenum Msg {\n    AddOne,\n}\n\nimpl Component for Model {\n    type Message = Msg;\n    type Properties = ();\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        Self {\n            link,\n            value: 0,\n        }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::AddOne => self.value += 1\n        }\n        true\n    }\n\n    fn change(&mut self, _props: Self::Properties) -> ShouldRender {\n        // Should only return \"true\" if new properties are different to\n        // previously received properties.\n        // This component has no properties so we will always return \"false\".\n        false\n    }\n\n    fn view(&self) -> Html {\n        html! {\n            <div>\n                <button onclick={self.link.callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n                <p>{ self.value }</p>\n            </div>\n        }\n    }\n}\n\n#[wasm_bindgen(start)]\npub fn run_app() {\n    App::<Model>::new().mount_to_body();\n}\n```\n\nこのテンプレートはルートに`Component`をセットアップし、`Model`と呼ばれるクリックしたら更新するボタンを作ります。\n`main()`の中にある`App::<Model>::new().mount_to_body()`がアプリをスタートしてページの`<body>`タグをマウントすることに特に注意してください。\n動的なプロパティでアプリをスタートしたい場合は代わりに`App::<Model>::new().mount_to_body_with_props(..)`を使うことで実現できます。\n\n最後に、アプリの中の`static`という名前のフォルダに`index.html`ファイルを追加してください。\n\n```bash\nmkdir static\n```\n\n```markup title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>Yew Sample App</title>\n        <script type=\"module\">\n            import init from \"./wasm.js\"\n            init()\n        </script>\n    </head>\n    <body></body>\n</html>\n```\n\n## アプリを動かす!\n\n[`wasm-pack`](https://drager.github.io/wasm-pack/book/)を使うのがアプリを動かすのに推奨される方法です。\nまだ`wasm-pack`をインストールしていない場合、`cargo install wasm-pack`でインストールして開発サーバーを動かしてみましょう:\n\n```bash\nwasm-pack build --target web --out-name wasm --out-dir ./static\n```\n\n`wasm-pack`はコンパイルされた WebAssembly と JavaScript ラッパーをまとめたものを`./static`ディレクトリに作り、\nアプリの WebAssembly バイナリを読み込んで動かします。\n\nそして、`./static`以下で好きなサーバーをファイルをサーブしてみましょう。\n例えば:\n\n```bash\ncargo +nightly install miniserve\nminiserve ./static --index index.html\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/getting-started/examples.mdx",
    "content": "---\ntitle: Examples\n---\n\nYew のリポジトリは[例](https://github.com/yewstack/yew/tree/v0.17/examples)がたくさんあります\n\\(メンテナンス状況は様々\\)。\n様々なフレームワークの機能の使い方を知るのにはそれらの例に取り組むのを勧めます。\nプルリクエストや Issue はウェルカムです。\n\n- [**Todo アプリ** ](https://github.com/yewstack/yew/tree/v0.17/examples/todomvc)\n- [**カスタムコンポーネント**](https://github.com/yewstack/yew/tree/v0.17/examples/custom_components)\n- [**マルチスレッド\\(エージェント\\)**](https://github.com/yewstack/yew/tree/v0.17/examples/multi_thread)\n- [**タイマーサービス**](https://github.com/yewstack/yew/tree/v0.17/examples/timer)\n- [**ネストしたコンポーネント**](https://github.com/yewstack/yew/tree/v0.16.0/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/more/css.mdx",
    "content": "---\ntitle: CSS\n---\n\n# CSS\n\n&lt;TODO&gt;\n\n統合的な CSS サポートについての提案はこちらにあります: [https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n## スタイルフレームワーク:\n\n今のところ、コミュニティメンバーは以下のスタイルフレームワークを開発しています。\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - JavaScript に依存しない Yew のスタイルフレームワーク\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - マテリアルデザインのコンポーネント\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI の CSS コンポーネント\n- [Yewtify](https://github.com/yewstack/yewtify) – Yew で Vuetify フレームワークで提供されている機能の実装\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/more/debugging.mdx",
    "content": "---\ntitle: Debugging\n---\n\n# デバッグ\n\n## パニック\n\nRust シンボルで良いスタックトレースをするには\n[`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook)クレートを使用してください。\n注意として、`cargo-web`でビルドされたものとは互換性がありません。\n\n## コンソールでのログ\n\n一般的に、Wasm の Web アプリはブラウザの API と連携することができ、`console.log`の API も例外ではありません。\nいつくかの選択肢があります:\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\nこのクレートは Rust の`log`クレートと親和性があります。\n\n```rust\n// セットアップ\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n}\n\n// 使用方法\nlog::info!(\"Update: {:?}\", msg);\n```\n\n### [`ConsoleService`](https://docs.rs/yew/latest/yew/services/console/struct.ConsoleService.html)\n\nこのサービスは Yew に含まれており、`\"services\"`の機能が有効化されている場合は利用可能です。\n\n```rust\n// 使用方法\nConsoleService::info(format!(\"Update: {:?}\", msg).as_ref());\n```\n\n## ソースマップ\n\n今のところは Rust/Wasm の Web アプリにはソースマップへの第一級のサポートがありません。\nもちろん、これは変更される可能性があります。これが当てはまらない場合、または進捗が見られる場合は、変更を提案してください！\n\n### 最新情報\n\n\\[2019 年 12 月\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> やらなければいけないことがまだたくさんあります。例えばツール側では Emscripten\\(Binaryen\\)と wasm-pack\\(wasm-bindgen\\)がそれらが実行する変換に関する DWARF 情報の更新をまだサポートしていません。\n\n\\[2020\\] [Rust Wasm デバッグガイド](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 残念なことに、WebAssembly のデバッグの物語はまだ未成熟です。ほとんどの Unix のシステムでは[DWARF](http://dwarfstd.org/)は実行中のプログラムをソースレベルで検査するためにデバッガに必要な情報をエンコードするために使用されます。Windows には同様の情報をエンコードする代替形式があります。現在、WebAssembly に相当するものはありません。\n\n\\[2019\\] [Rust Wasm ロードマップ](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> デバッグはトリッキーです。なぜなら、多くの話はこの活動チームの手の届かないところにあり、WebAssembly の標準化団体とブラウザ開発者ツールを実装している人たちの両方に依存しているからです。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/more/roadmap.mdx",
    "content": "---\ntitle: Roadmap\ndescription: The planned feature roadmap for the Yew framework\n---\n\n# ロードマップ\n\n## 優先順位\n\nフレームワークの今後の機能やフォーカスの優先順位は、コミュニティによって決定されます。2020 年の春には、プロジェクトの方向性についてのフィードバックを集めるために開発者アンケートが行われました。その概要は [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) で見ることができます。\n\n:::note\n主要な取り組みの状況は、Yew の Github の[Project board](https://github.com/yewstack/yew/projects)で確認できます。\n:::\n\n## 焦点\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Top Requested Features\n\n1. [関数型コンポーネント](https://github.com/yewstack/yew/projects/3)\n2. [Component ライブラリ](https://github.com/yewstack/yew/projects/4)\n3. より良い状態管理\n4. [サーバーサイドでのレンダリング](https://github.com/yewstack/yew/projects/5)\n\n### Production Readiness\n\n- テストカバレッジの向上\n- バイナリサイズ\n- [ベンチマークのパフォーマンス](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- チュートリアルを作る\n- プロジェクトのセットアップをシンプルにする\n\n### Pain Points\n\n- [Component のボイラープレート](https://github.com/yewstack/yew/issues/830)\n- Fetch API\n- [エージェント](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20/more/testing.mdx",
    "content": "---\ntitle: Testing apps\ndescription: Testing your app\n---\n\n# Testing\n\n&lt;TODO&gt;\n\n## wasm_bindgen_test\n\nRust Wasm ワーキンググループは wasm_bindgen_test というフレームワークをメンテナンスしており、組み込みの #[test] プロシージャルマクロの動作と同様の方法でブラウザでテストを実行することができます。詳細は、[Rust Wasm 活動グループのドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)に記載されています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.20.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.20\",\n    \"description\": \"The label for version 0.20\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Using Basic Web Technologies In Yew\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew's Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may need in one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[function_component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[function_component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: 'Low level details about the framework'\n---\n\n# Low-level library internals\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '最適化とベストプラクティス'\nsidebar_label: Optimizations\ndescription: 'Make your app faster'\n---\n\n## 効果的にスマートポインタを使う\n\n**注意: このセクションで使われている用語がわからなければ Rust book は\n[スマートポインタについての章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\nがあり、非常に有用です。**\n\n再レンダリング時にpropsを作成するために大量のデータをクローンすることを避けるために、\nデータそのものではなく、データへの参照のみをクローンするスマートポインタを使用できます。\n実際のデータではなく、propsと子コンポーネントで関連するデータへの参照を渡すことで、\n子コンポーネントでデータを変更する必要があるまでデータのクローンを避けることができます。\nその場合、`Rc::make_mut`を使用してクローンし、変更したいデータへの可変参照を取得できます。\n\nこれにより、propの変更がコンポーネントの再レンダリングを必要とするかどうかを判断する際に、\n`Component::changed`でさらなる利点がもたらされます。これは、データの値を比較する代わりに、\n基礎となるポインタアドレス（つまり、データが格納されているマシンのメモリ上の位置）を\n比較できるためです。2つのポインタが同じデータを指している場合、それらが指すデータの値は\n同じでなければなりません。ただし、逆は必ずしも真ではないことに注意してください！\n2つのポインタアドレスが異なっていても、基礎となるデータは同じかもしれません。\nこの場合、基礎となるデータを比較する必要があります。\n\nこの比較を行うには、`PartialEq`（等値演算子`==`を使用してデータを比較する際に自動的に使用される）を\n使用するのではなく、`Rc::ptr_eq`を使用する必要があります。Rustのドキュメントには\n[`Rc::ptr_eq`についての詳細](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)があります。\n\nこの最適化は、`Copy`を実装していないデータ型に最も有用です。データを安価にコピーできる場合、\nスマートポインタの背後に置く価値はありません。`Vec`、`HashMap`、`String`のようにデータが重くなる可能性のある\n構造体の場合、スマートポインタを使用するとパフォーマンスの改善が見込まれます。\n\nこの最適化は、値が子によって決して更新されない場合に最も効果的であり、\n親によってもめったに更新されない場合はさらに効果的です。これにより、`Rc<_>`は\nピュアコンポーネントのプロパティ値をラップするのに適した選択となります。\n\nただし、子コンポーネントでデータを自分でクローンする必要がない限り、\nこの最適化は無用であるだけでなく、参照カウントの不必要なコストも追加することに注意する必要があります。\nYewのpropsはすでに参照カウントされており、内部的にデータのクローンは発生しません。\n\n## ビュー関数\n\nコードの可読性のために、`html!`のセクションを独自の関数に移行することはしばしば意味があります。\nこれにより、インデントの量が減るためコードがより読みやすくなるだけでなく、\n良い設計パターンも促進されます。特に、これらの関数は複数の場所から呼び出すことができるため、\n記述する必要のあるコードの量が減り、構成可能なアプリケーションの構築に役立ちます。\n\n## ピュアコンポーネント\n\nピュアコンポーネントは、状態を変更せず、コンテンツを表示し、\n通常の可変コンポーネントにメッセージを伝播するだけのコンポーネントです。\nビュー関数とは異なり、式構文（\\(`{some_view_function()}`\\)）ではなく\nコンポーネント構文（\\(`<SomePureComponent />`\\)）を使用して`html!`マクロ内から使用でき、\n実装によってはメモ化できます（これは、関数が一度呼び出されるとその値が「保存」され、\n同じ引数で複数回呼び出された場合、値を再計算する必要がなく、\n最初の関数呼び出しから保存された値を返すことができることを意味します）。\nこれにより、同一のpropsに対する再レンダリングを防ぎます。\nYewは内部的にpropsを比較し、propsが変更された場合のみUIが再レンダリングされます。\n\n## ワークスペースを使用してコンパイル時間を短縮する\n\n間違いなく、Yewを使用する最大の欠点は、Yewアプリのコンパイルに長い時間がかかることです。\nプロジェクトのコンパイルにかかる時間は、`html!`マクロに渡されるコードの量に関連しているようです。\nこれは小規模なプロジェクトではそれほど問題にならない傾向がありますが、大規模なアプリケーションでは、\nアプリケーションに加えられた各変更に対してコンパイラが行う必要がある作業量を最小限に抑えるために、\nコードを複数のクレートに分割することが理にかなっています。\n\n可能なアプローチの1つは、メインクレートにルーティング/ページ選択を処理させ、\n各ページに異なるクレートを作成することです。各ページは異なるコンポーネントか、\n`Html`を生成する大きな関数になる可能性があります。アプリケーションの異なる部分を含む\nクレート間で共有されるコードは、プロジェクトが依存する別のクレートに格納できます。\n最良のケースでは、各コンパイルですべてのコードを再ビルドすることから、\nメインクレートと1つのページクレートのみを再ビルドすることになります。\n最悪の場合、「共通」クレートで何かを編集すると、その共通に共有されるクレートに依存する\nすべてのコード（おそらく他のすべて）をコンパイルする元の状態に戻ってしまいます。\n\nメインクレートが重すぎる場合、または深くネストされたページ（\\(例：別のページの上にレンダリングされるページ\\)）で\n迅速に反復したい場合は、サンプルクレートを使用してメインページの簡略化された実装を作成し、\n作業中のコンポーネントを追加でレンダリングできます。\n\n## バイナリサイズを小さくする\n\n- Rust のコードを最適化する\n- `cargo.toml` \\( release profile を定義 \\)\n- `wasm-opt`を用いて wasm のコードを最適化する\n\n**注意: バイナリサイズを小さくするのについては[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)に詳しく書いてあります。**\n\n### Cargo.toml\n\n`Cargo.toml`で`[profile.release]`のセクションに設定を書き込むことでリリースビルドを小さくすることが可能です。\n\n```toml, title=Cargo.toml\n[profile.release]\n# バイナリに含むコードを少なくする\npanic = 'abort'\n# コードベース全体での最適化 ( 良い最適化だがビルドが遅くなる)\ncodegen-units = 1\n# サイズの最適化( よりアグレッシブに )\nopt-level = 'z'\n# サイズの最適化\n# opt-level = 's'\n# プログラム全体の分析によるリンク時最適化\nlto = true\n```\n\n### Nightly Cargo設定\n\nrustとcargoの実験的なナイトリー機能から追加の利点を得ることもできます。\n`trunk`でナイトリーツールチェーンを使用するには、`RUSTUP_TOOLCHAIN=\"nightly\"`環境変数を設定します。\nその後、`.cargo/config.toml`で不安定なrustc機能を設定できます。\n設定を理解するには、[unstable features]のドキュメント、特に[`build-std`]と\n[`build-std-features`]に関するセクションを参照してください。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# rust-srcコンポーネントが必要です。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nナイトリーrustコンパイラには、[このような](https://github.com/yewstack/yew/issues/2696)バグが含まれている可能性があり、\n時折注意と調整が必要です。これらの実験的オプションは慎重に使用してください。\n:::\n\n### wasm-opt\n\n更に`wasm`のコードのサイズを最適化することができます。\n\nThe Rust Wasm Book には Wasm バイナリのサイズを小さくすることについてのセクションがあります:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- `wasm-pack`でデフォルトの`wasm`のコードをリリースビルド時に最適化する\n- `wasm-opt`によって直接`wasm`ファイルを最適化する\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### yew/examples/にある例を小さなサイズでビルドする\n\n注意: `wasm-pack`は Rust と Wasm のコードへの最適化を組み合わせます。`wasm-bindgen`はこの例では Rust のサイズ最適化を用いていません。\n\n| 使用したツール              | サイズ |\n| :-------------------------- | :----- |\n| wasm-bindgen                | 158KB  |\n| wasm-bindgen + wasm-opt -Os | 116KB  |\n| wasm-pack                   | 99 KB  |\n\n## 参考文献:\n\n- [The Rust Book のスマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [the Rust Wasm Book でのバイナリサイズを小さくすることについて](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust profiles についてのドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[function_component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/server-side-rendering.md",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[function_component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'ライフサイクル'\ndescription: 'コンポーネントとそのライフサイクルフック'\n---\n\n`Component` トレイトには実装が必要なメソッドがいくつかあります。Yew はコンポーネントのライフサイクルの異なる段階でこれらを呼び出します。\n\n## ライフサイクル\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## ライフサイクルのメソッド\n\n### Create\n\nコンポーネントが作られると、親コンポーネントからプロパティを受け取り、`create` メソッドに渡される `Context<Self>` 内に格納されます。\nプロパティはコンポーネントの状態を初期化するのに使われ、\"link\"はコールバックを登録したりコンポーネントにメッセージを送るのに使われます。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nコンポーネントは`view()`メソッドによってレイアウトを宣言します。\nYew は`html!`マクロによって HTML と SVG ノード、リスナー、子コンポーネントを宣言できます。\nマクロは React の JSX のような動きをしますが、JavaScript の代わりに Rust の式を用います。\nYew は Svelte のように、`onclick={onclick}` の代わりに `{onclick}` と書くことができる省略構文を提供しています。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n使い方については[`html!`ガイド](concepts/html/introduction.mdx)をご確認ください。\n\n### Rendered\n\n`rendered()`コンポーネントのライフサイクルのメソッドは`view()`が処理されて Yew がコンポーネントをレンダリングした後、\nブラウザがページを更新する前に呼ばれます。\nコンポーネントは、コンポーネントが要素をレンダリングした後にのみ実行できるアクションを実行するため、このメソッドを実装したい場合があります。\nコンポーネントが初めてレンダリングされたかどうかは `first_render` パラメータで確認できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nライフサイクルメソッドは実装の必要がなく、デフォルトでは何もしません。\n:::\n\n### Update\n\nコンポーネントは動的で、非同期メッセージを受信するために登録することができます。\nライフサイクルメソッド `update()` はメッセージごとに呼び出されます。\nこれにより、コンポーネントはメッセージが何であったかに基づいて自身を更新し、自身を再レンダリングする必要があるかどうかを判断することができます。\nメッセージは、HTML 要素リスナーによってトリガーされたり、子コンポーネント、エージェント、サービス、または Futures によって送信されたりします。\n\n`update()`がどのようなのかについての例は以下の通りです:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nコンポーネントは親によって再レンダリングされることがあります。\nこのような場合、新しいプロパティを受け取り、再レンダリングを選択する可能性があります。\nこの設計では、プロパティを変更することで、親から子へのコンポーネントの通信が容易になります。\nprops が変更されたときにコンポーネントを再レンダリングするデフォルト実装があります。\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods but are only caused when trying to update\nthe same component after every render, when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it is often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample, you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to the component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nプロパティは、子コンポーネントと親コンポーネントが互いに通信できるようにします。\n各コンポーネントには、親から渡されるものを記述する関連付けられたプロパティタイプがあります。\n理論的には、これは `Properties` trait を実装する任意のタイプにすることができますが、実際には\n各フィールドがプロパティを表す構造体以外にする理由はありません。\n\n## マクロの継承\n\n`Properties`を自分で実装しようとせず、代わりに`#[derive(Properties)]`を使ってください。\n`Properties`を継承した型は`PartialEq`も実装していなければいけません。\n\n### フィールド属性\n\nデフォルトでは、`Properties` を導出する構造体内のフィールドは必須です。\n以下の属性を使うと、props に初期値を与えることができ、他の値に設定されない限りこの値が使用されます。\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\nもし可能なら props で `PartialEq` を継承するのが良いかもしれません。\n`PartialEq`を使うことで、不必要な再レンダリングを避けることができます\n(これについては、**最適化とベストプラクティス**のセクションで説明しています)。\n\n## プロパティを使用する際のメモリと速度のオーバーヘッド\n\n`Component::view`ではコンポーネントの状態への参照を取り、それを使って `Html` を作成します。\nしかし、プロパティは自身の値です。\nつまり、それらを作成して子コンポーネントに渡すためには、`view` 関数で提供される参照を所有する必要があるのです。\nこれは所有する値を取得するためにコンポーネントに渡される参照を暗黙のうちにクローンすることで行われます。\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: Refs\ndescription: Out-of-band DOM access\n---\n\n`ref`は、任意の HTML 要素やコンポーネントの内部で、割り当てられている DOM`Element`を取得するために使用することができます。\nこれは、`view` ライフサイクルメソッドの外で DOM に変更を加えるために使用できます。\n\nこれは、キャンバスの要素を取得したり、ページの異なるセクションにスクロールしたりするのに便利です。\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\n構文は以下の通りです:\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/agents.mdx",
    "content": "---\ntitle: Agents\ndescription: Yew's Actor System\n---\n\nエージェントは Angular の[サービス](https://angular.io/guide/architecture-services)に似ており\\(ただし依存性インジェクションはありません\\)、\n[アクターモデル](https://en.wikipedia.org/wiki/Actor_model)を提供します。\nエージェントはコンポーネント階層のどこに位置するかに関わらず、コンポーネント間でメッセージをルーティングしたり、共有状態を作成したり、UI をレンダリングするメインスレッドから計算量の多いタスクをオフロードするために使用することができます。\nまた、Yew アプリケーションがタブをまたいで通信できるようにするためのエージェントのサポートも\\(将来的には\\)計画されています。\n\nエージェントが並行に動くように Yew は[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)を使用しています。\n\n## ライフサイクル\n\n![エージェントのライフサイクル](https://user-images.githubusercontent.com/42674621/79125224-b6481d80-7d95-11ea-8e6a-ab9b52d1d8ac.png)\n\n## エージェントの種類\n\n### Reaches\n\n- Context - Context エージェントのインスタンスは、常に最大 1 つ存在します。\n  Bridges は、UI スレッド上で既にスポーンされたエージェントをスポーンするか、接続します。\n  これは、コンポーネントまたは他のエージェント間の状態を調整するために使用することができます。\n  このエージェントに Bridges が接続されていない場合、このエージェントは消滅します。\n\n- Job - 新しいブリッジごとに UI スレッド上で新しいエージェントをスポーンします。\n  これは、ブラウザと通信する共有されているが独立した動作をコンポーネントの外に移動させるのに適しています。\n  (TODO 確認) タスクが完了すると、エージェントは消えます。\n\n- Public - Context と同じですが、独自の web worker で動作します。\n\n- Private - Job と同じですが、独自の web worker で動作します。\n\n- Global \\(WIP\\)\n\n## エージェントとコンポーネントのやり取り\n\n### Bridges\n\nBridge は、エージェントとコンポーネント間の双方向通信を可能にします。\nまた、Bridge はエージェント同士の通信を可能にします。\n\n### Dispatchers\n\nDispatcher は、コンポーネントとエージェント間の一方向通信を可能にします。\nDispatcher は、コンポーネントがエージェントにメッセージを送信することを可能にします。\n\n## オーバーヘッド\n\n独自の独立した web worker(プライベートとパブリック)にあるエージェントは、送受信するメッセージにシリアライズするオーバーヘッドが発生します。\n他のスレッドとの通信には[bincode](https://github.com/servo/bincode)を使用するので、関数を呼び出すよりもコストはかなり高くなります。\n計算コストがメッセージの受け渡しコストを上回る場合を除き、ロジックを UI スレッドエージェント\\(Job または Context\\)に格納する必要があります。\n\n## 参考資料\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib)の例でコンポーネントがどのようにエージェントと通信させているかがわかります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, function_component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[function_component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[function_component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[function_component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[function_component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[function_component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[function_component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[function_component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{function_component, html, Html};\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[function_component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Properties)'\ndescription: '親子コンポーネントの通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nプロパティ (Properties) は通常 \"Props\" と略されます。\n\n:::\n\nプロパティ (Properties) はコンポーネントのパラメータであり、Yew はこれらのパラメータを監視できます。\n\nコンポーネントのプロパティで型を使用する前に、その型は `Properties` トレイトを実装している必要があります。\n\n## リアクティブ性\n\n再レンダリング時に、Yew は仮想DOMを調整する際にプロパティが変更されたかどうかを確認し、ネストされたコンポーネントを再レンダリングする必要があるかどうかを判断します。これにより、Yew は非常にリアクティブなフレームワークと見なされます。親コンポーネントからの変更は常に下位に伝播し、ビューはプロパティ/状態からのデータと常に同期します。\n\n:::tip\n\nまだ [チュートリアル](../../tutorial) を完了していない場合は、このリアクティブ性を自分でテストしてみてください！\n\n:::\n\n## 派生マクロ\n\nYew は、構造体に `Properties` トレイトを簡単に実装できる派生マクロを提供します。\n\n`Properties` を派生する型は、Yew がデータ比較を行えるように `PartialEq` も実装している必要があります。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 関数コンポーネントでの使用\n\n属性 `#[function_component]` は、関数の引数で Props を選択的に受け取ることを可能にします。それらを提供するには、`html!` マクロ内の属性を通じて割り当てることができます。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{props.is_loading.clone()}</> }\n}\n\n// そしてプロパティを提供します\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{function_component, html, Html};\n\n\n\n\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 提供するプロパティはありません\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld />}\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生マクロフィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。\n以下の属性を使用すると、親コンポーネントがそれらを設定しなかった場合にデフォルト値を提供することができます。\n\n:::tip\n属性は Rustdoc によって生成されたドキュメントには表示されません。属性のドキュメント文字列には、その属性がオプションであるかどうか、および特定のデフォルト値があるかどうかを記載する必要があります。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n`Default` トレイトを使用して、フィールド型のデフォルト値でプロパティ値を初期化します。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading.clone() {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// デフォルト値を使用する\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// またはデフォルト値を上書きしない\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。\n例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。プロパティが構築されるときに、式が評価され、明示的な値が与えられていない場合に適用されます。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or(\"Bob\".to_string())]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// デフォルト値を使用する\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// またはデフォルト値を上書きしない\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n属性値を初期化するために `function` を呼び出します。`function` は `FnMut() -> T` シグネチャを持つ必要があり、ここで `T` はフィールドの型です。このプロパティに明示的な値が与えられていない場合、その関数が呼び出されます。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\nfn create_default_name() -> String {\n    \"Bob\".to_string()\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// デフォルト値を使用する\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// またはデフォルト値を上書きしない\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたスマートポインタとして渡されます。これにより、コンポーネントツリー内のプロパティに対して共有ポインタが1つだけ渡されるため、プロパティ全体をクローンする高コストを節約できます。\n\n:::tip\n`AttrValue` はプロパティ値に使用するカスタムタイプであり、これにより String やその他のクローンコストが高いタイプとして定義する必要がなくなります。\n:::\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、プロパティや基本式 (`Foo { ..base }`) を使用することはできません。タイプパスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or(AttrValue::from(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n#[function_component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = props! {\n        Props {} // 名前属性を指定する必要はありません\n    };\n    // highlight-end\n    html! {<HelloWorld ..pre_made_props />}\n}\n```\n\n## 評価順序\n\n属性は指定された順序で評価されます。以下の例を参照してください：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## アンチパターン\n\nほとんどのRust型はプロパティとして渡すことができますが、避けるべきアンチパターンがいくつかあります。これらには以下が含まれますが、これに限定されません：\n\n1. `String` 型を `AttrValue` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `String` のクローンは高コストです。プロパティ値がフックやコールバックと一緒に使用される場合、通常クローンが必要です。`AttrValue` は参照カウントされた文字列 (`Rc<str>`) または `&'static str` であり、非常に安価にクローンできます。<br />\n   **注意**：`AttrValue` は内部的には [implicit-clone](https://crates.io/crates/implicit-clone) からの `IString` です。詳細はそのパッケージを参照してください。\n2. 内部可変性を使用する。 <br />\n   **なぜ悪いのか？** 内部可変性（例えば `RefCell`、`Mutex` など）は _通常_ 避けるべきです。これにより再レンダリングの問題が発生する可能性があり（Yewは状態が変更されたことを認識しません）、手動で再レンダリングを強制する必要があるかもしれません。すべてのものと同様に、適切な使用場所があります。慎重に使用してください。\n3. `Vec<T>` 型を `IArray<T>` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `Vec<T>` も `String` と同様にクローンのコストが高いです。`IArray<T>` は参照カウントされたスライス (`Rc<[T]>`) または `&'static [T]` であり、非常に安価にクローンできます。<br />\n   **注意**：`IArray<T>` は [implicit-clone](https://crates.io/crates/implicit-clone) からインポートできます。詳細はそのパッケージを参照してください。\n4. 新しい発見があるかもしれません。早く知っておきたかったエッジケースに遭遇しましたか？問題を作成するか、このドキュメントに修正のPRを提供してください。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) は実験的なパッケージで、関数の引数に基づいて動的にProps構造体を作成することを可能にします。プロパティ構造体が再利用されない場合、これは有用かもしれません。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/html/components.mdx",
    "content": "---\ntitle: Components\ndescription: Create complex layouts with component hierarchies\n---\n\n## 基本\n\n`Component`を実装しているあらゆる型は`html!`マクロの中で使えます:\n\n```rust\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponent prop1=\"lorem\" prop2=\"ipsum\" />\n\n        // With the whole set of props provided at once\n        <MyComponent ..props />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponent prop2=\"lorem\" ..props />\n    </>\n}\n```\n\n## ネスト\n\n`children`フィールドが`Properties`の中にある場合はコンポーネントは子に渡されます。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <Container>\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n}\n```\n\n```rust title=\"container.rs\"\npub struct Container(Props);\n\n#[derive(Properties, Clone)]\npub struct Props {\n    pub children: Children,\n}\n\nimpl Component for Container {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n       html! {\n           <div id=\"container\">\n               { self.0.children.clone() }\n           </div>\n       }\n    }\n}\n```\n\n:::note\n`Properties`を継承した型は`Clone`を実装していなければいけません。\nこれは`#[derive(Properties, Clone)]`を使うか手で`Clone`を実装すれば良いです。\n:::\n\n## Props とネストした子コンポーネント\n\nネストしたコンポーネントのプロパティは格納しているコンポーネントの型が子である場合はアクセス可能、または変更可能です。\n以下の例では`List`コンポーネントは`ListItem`コンポーネントをラップできています。\n実際の使用においてこのパターンの例については`yew-router`のソースコードを確認してみてください。\nより進んだ例としては Yew のメインのリポジトリにある`nested-list`を確認してみてください。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n}\n```\n\n```rust title=\"list.rs\"\npub struct List(Props);\n\n#[derive(Properties, Clone)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\nimpl Component for List {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n        html!{{\n            for self.0.children.iter().map(|mut item| {\n                item.props.value = format!(\"item-{}\", item.props.value);\n                item\n            })\n        }}\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/html/elements.mdx",
    "content": "---\ntitle: Elements\ndescription: Both HTML and SVG elements are supported\n---\n\n## タグ構造\n\n要素のタグは`<... />`のような自己完結タグか、開始タグに対応した終了タグを持っている必要があります。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Open - Close-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"></div>\n}\n```\n\n<!--Invalid-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n}\n```\n\n<!--Self-closing-->\n\n```rust\nhtml! {\n  <input id=\"my_input\" />\n}\n```\n\n<!--Invalid-->\n\n```rust\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n:::note\n便利さのために、*普通は*終了タグを必要とする要素は自己完結タグとすることが**できます**。\n例えば`html! { <div class=\"placeholder\" /> }`と書くのは有効です。\n:::\n\n## 子\n\n複雑にネストした HTML や SVG のレイアウトを書くのには以下のようにするのが楽です:\n\\*\\*\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--HTML-->\n\n```rust\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n}\n```\n\n<!--SVG-->\n\n```rust\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <feGaussianBlur stdDeviation=\"2\"/>\n                <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## クラス\n\n要素へのクラスを特定する便利なやり方はたくさんあります:\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Literal-->\n\n```rust\nhtml! {\n  <div class=\"container\"></div>\n}\n```\n\n<!--Multiple-->\n\n```rust\nhtml! {\n  <div class=\"container center-align\"></div>\n}\n```\n\n<!--Interpolated-->\n\n```rust\nhtml! {\n  <div class={format!(\"{}-container\", size)}></div>\n}\n```\n\n<!--Expression-->\n\n```rust\nhtml! {\n  <div class={self.classes()}></div>\n}\n```\n\n<!--Tuple-->\n\n```rust\nhtml! {\n  <div class={(\"class-1\", \"class-2\")}></div>\n}\n```\n\n<!--Vector-->\n\n```rust\nhtml! {\n  <div class={vec![\"class-1\", \"class-2\"]}></div>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## リスナー\n\nリスナー属性はクロージャのラッパーである`Callback`に渡される必要があります。\nコールバックをどのように作るかはアプリをリスナーイベントにどう反応させたいかによります。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Component handler-->\n\n```rust\nstruct MyComponent {\n    link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => {\n                // Handle Click\n            }\n        }\n    }\n\n    fn view(&self) -> Html {\n        // Create a callback from a component link to handle it in a component\n        let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Agent Handler-->\n\n```rust\nstruct MyComponent {\n    worker: Dispatcher<MyWorker>,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent {\n            worker: MyWorker::dispatcher()\n        }\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // Create a callback from a worker to handle it in another context\n        let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Other Cases-->\n\n```rust\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // Create an ephemeral callback\n        let click_callback = Callback::from(|| {\n            ConsoleService::log(\"clicked!\");\n        });\n\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## イベントの型\n\n:::note\n以下のテーブルにある全てのイベントの型は`yew::events`で再エクスポートされています。\nAll the event types mentioned in the following table are re-exported under `yew::events`. Using the types from\n`yew::events` makes it easier to ensure version compatibility than if you were to manually include `web-sys`\nor `stdweb` as dependencies in your crate because you won't end up using a version which conflicts with\nthe version Yew specifies.\n:::\n\n| イベント名                  | `web_sys` イベント型                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [ChangeData](https://docs.rs/yew/latest/yew/events/enum.ChangeData.html)              |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.htmk)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputData](https://docs.rs/yew/latest/yew/events/struct.InputData.html)              |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/html/introduction.mdx",
    "content": "---\ntitle: Introduction\ndescription: The procedural macro for generating HTML and SVG\nslug: /concepts/html\n---\n\n`html!`マクロによって HTML と SVG のコードを宣言的に書くことができます。\nJSX \\(HTML のようなコードを JavaScript 内部に書くことができる JavaScript の拡張\\) に似ています。\n\n**重要な注意**\n\n1. `html!`マクロはルートの HTML ノードのみ受け付けます \\([フラグメントかイテレータを使う](./lists.mdx)ことでやり取りできます\\)\n2. 空の`html! {}`の呼び出しは可能ですが何もレンダリングしません\n3. リテラルはクオーテーションがつけられ、ブレースで囲う必要があります: `html! { \"Hello, World\" }`\n\n:::note\n`html!`マクロはコンパイラのデフォルトの再帰の上限に簡単に達してしまいます。\nもしコンパイラエラーに遭遇した場合はその値を押し出すといいかもしれません。\nクレートのルート\\(つまり、`lib.rs`か`main.rs`\\)で`#![recursion_limit=\"1024\"]`のような属性を使えば解決します。\n\n詳しくは[公式ドキュメント](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)と[Stack Overflow の質問](https://stackoverflow.com/questions/27454761/what-is-a-crate-attribute-and-where-do-i-add-it)を見てみてください。\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/html/lists.mdx",
    "content": "---\ntitle: Lists\n---\n\n## フラグメント\n\n`html!`マクロは常にルートノードが 1 つであることを要求します。\nこの制限のために、空のタグを使って内容をラップすると良いでしょう。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Valid-->\n\n```rust\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n}\n```\n\n<!--Invalid-->\n\n```rust\n/* error: only one root html element allowed */\n\nhtml! {\n    <div></div>\n    <p></p>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## イテレータ\n\nYew はイテレータから HTML をビルドするのに 2 つの方法をサポートしています。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Syntax Type 1-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { self.props.items.iter().map(renderItem).collect::<Html>() }\n    </ul>\n}\n```\n\n<!--Syntax Type 2-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { for self.props.items.iter().map(renderItem) }\n    </ul>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: Literals and Expressions\n---\n\n## リテラル\n\n式が`Display`を実装した型を解決する場合、文字列に変換されて DOM に[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text)ノードとして挿入されます。\n\nテキストは式として処理されるため、全ての表示される内容は`{}`ブロックによって囲まれる必要があります。\nこれは Yew のアプリと通常の HTML の構文で最も異なる点です。\n\n```rust\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n}\n```\n\n## 式\n\nHTML に`{}`ブロックを使って式を挿入することができます。\n\n```rust\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n}\n```\n\n式を関数やクロージャに分離するのはコードの可読性の観点から有効なことがあります。\n\n```rust\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/concepts/router.mdx",
    "content": "---\ntitle: Router\ndescription: Yew's official router\n---\n\n[crates.io にあるルータ](https://crates.io/crates/yew-router)\n\nシングルページアプリケーション\\(SPA\\)におけるルータは URL よってページを出し分けます。\nリンクがクリックされたときに異なるリソースを要求するというデフォルトの動作の代わりに、ルータはアプリケーション内の有効なルートを指すように URL をローカルに設定します。\nルータはこの変更を検出してから、何をレンダリングするかを決定します。\n\n## コアとなる要素\n\n### `Route`\n\nURL 内のドメインの後のすべてを表す文字列と、オプションで history API に保存されている状態を含みます。\n\n### `RouteService`\n\nブラウザとやりとりしてルーティングを決めます。\n\n### `RouteAgent`\n\nRouteService を所有し、ルートが変更された際の更新を調整するために使用します。\n\n### `Switch`\n\n`Switch`トレイトは`Route`をトレイトの実装する側の間で変換するために用いられます。\n\n### `Router`\n\nRouter コンポーネントは RouteAgent とやり取りし、エージェントがどうスイッチするか Routes を自動的に解決します。\nこれは、結果として得られるスイッチがどのように Html に変換されるかを指定できるようにするため、props を介して公開されます。\n\n## ルータをどのように使うか\n\nまず、アプリケーションのすべての状態を表す型を作成します。\nこれは通常は列挙型ですが、構造体もサポートされており、`Switch` を実装した他のアイテムを内部に入れ子にすることができることに注意してください。\n\n次に、`Switch`を型に継承させなければいけません。\n列挙型の場合は全ての variant は`#[to = \"/some/route\"]`とアノテーションされている必要があり、代わり構造体を用いている場合は構造体宣言が外部から見えるようにしてなければいけません。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n  #[to=\"/\"]\n  Home\n}\n```\n\n:::caution\n`Switch`用の派生マクロによって生成された実装は、各 variant を最初から最後までの順にマッチさせようとするので、指定した`to`アノテーションのうち 2 つのルートにマッチする可能性がある場合は、最初のルートがマッチし、2 つ目のルートは試行されないことに注意してください。例えば、以下の`Switch`を定義した場合、マッチするルートは`AppRoute::Home`だけになります。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/\"]\n  Home,\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n}\n```\n\n:::\n\nまた、`#[to = \"\"]`アノテーションの中で`{}`のバリエーションを使ってセクションをキャプチャすることもできます。\n`{}`は、次の区切り文字\\(コンテキストに応じて \"/\", \"?\", \"&\", \"#\" のいずれか\\) までのテキストをキャプチャします。\n`{*}`は、次の文字が一致するまでテキストをキャプチャすることを意味します。\n`{<number>}`は、指定した数の区切り文字が見つかるまでテキストをキャプチャすることを意味します\n\\(例: `{2}`は区切り文字が 2 つ見つかるまでキャプチャします\\)。\n\n名前付きフィールドを持つ構造体や列挙型の場合は、キャプチャグループ内で以下のようにフィールドの名前を指定する必要があります。\n`{user_name}` または `{*:age}` のように、キャプチャグループ内でフィールドの名前を指定しなければなりません。\n\nSwitch トレイトは文字列よりも構造化されたキャプチャグループで動作します。\n`Switch`を実装した任意の型を指定することができます。\nそのため、キャプチャグループが `usize` であることを指定することができ、URL のキャプチャ部分がそれに変換できない場合、variant はマッチしません。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: Build a sample app\n---\n\nはじめに、Rust の新規ライブラリを作りましょう(**重要:** `--lib`フラグを渡すことで*バイナリ*ではなく*ライブラリ*を作ってください)\n\n```bash\ncargo new --lib yew-app && cd yew-app\n```\n\n依存ライブラリに`yew`と`wasm-bindgen`を追加してください \\(最新バージョンについては[こちら](https://docs.rs/yew)を参照してください\\)\n\n```toml title=\"Cargo.toml\"\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nauthors = [\"Yew App Developer <name@example.com>\"]\nedition = \"2018\"\n\n[lib]\ncrate-type = [\"cdylib\", \"rlib\"]\n\n[dependencies]\nyew = \"0.17\"\nwasm-bindgen = \"0.2\"\n```\n\n以下のテンプレートを `src/lib.rs`ファイルにコピーしてください:\n\n```rust title=\"src/lib.rs\"\nuse wasm_bindgen::prelude::*;\nuse yew::prelude::*;\n\nstruct Model {\n    link: ComponentLink<Self>,\n    value: i64,\n}\n\nenum Msg {\n    AddOne,\n}\n\nimpl Component for Model {\n    type Message = Msg;\n    type Properties = ();\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        Self {\n            link,\n            value: 0,\n        }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::AddOne => self.value += 1\n        }\n        true\n    }\n\n    fn change(&mut self, _props: Self::Properties) -> ShouldRender {\n        // Should only return \"true\" if new properties are different to\n        // previously received properties.\n        // This component has no properties so we will always return \"false\".\n        false\n    }\n\n    fn view(&self) -> Html {\n        html! {\n            <div>\n                <button onclick={self.link.callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n                <p>{ self.value }</p>\n            </div>\n        }\n    }\n}\n\n#[wasm_bindgen(start)]\npub fn run_app() {\n    App::<Model>::new().mount_to_body();\n}\n```\n\nこのテンプレートはルートに`Component`をセットアップし、`Model`と呼ばれるクリックしたら更新するボタンを作ります。\n`main()`の中にある`App::<Model>::new().mount_to_body()`がアプリをスタートしてページの`<body>`タグをマウントすることに特に注意してください。\n動的なプロパティでアプリをスタートしたい場合は代わりに`App::<Model>::new().mount_to_body_with_props(..)`を使うことで実現できます。\n\n最後に、アプリの中の`static`という名前のフォルダに`index.html`ファイルを追加してください。\n\n```bash\nmkdir static\n```\n\n```markup title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>Yew Sample App</title>\n        <script type=\"module\">\n            import init from \"./wasm.js\"\n            init()\n        </script>\n    </head>\n    <body></body>\n</html>\n```\n\n## アプリを動かす!\n\n[`wasm-pack`](https://drager.github.io/wasm-pack/book/)を使うのがアプリを動かすのに推奨される方法です。\nまだ`wasm-pack`をインストールしていない場合、`cargo install wasm-pack`でインストールして開発サーバーを動かしてみましょう:\n\n```bash\nwasm-pack build --target web --out-name wasm --out-dir ./static\n```\n\n`wasm-pack`はコンパイルされた WebAssembly と JavaScript ラッパーをまとめたものを`./static`ディレクトリに作り、\nアプリの WebAssembly バイナリを読み込んで動かします。\n\nそして、`./static`以下で好きなサーバーをファイルをサーブしてみましょう。\n例えば:\n\n```bash\ncargo +nightly install miniserve\nminiserve ./static --index index.html\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/getting-started/examples.mdx",
    "content": "---\ntitle: Examples\n---\n\nYew のリポジトリは[例](https://github.com/yewstack/yew/tree/v0.17/examples)がたくさんあります\n\\(メンテナンス状況は様々\\)。\n様々なフレームワークの機能の使い方を知るのにはそれらの例に取り組むのを勧めます。\nプルリクエストや Issue はウェルカムです。\n\n- [**Todo アプリ** ](https://github.com/yewstack/yew/tree/v0.17/examples/todomvc)\n- [**カスタムコンポーネント**](https://github.com/yewstack/yew/tree/v0.17/examples/custom_components)\n- [**マルチスレッド\\(エージェント\\)**](https://github.com/yewstack/yew/tree/v0.17/examples/multi_thread)\n- [**タイマーサービス**](https://github.com/yewstack/yew/tree/v0.17/examples/timer)\n- [**ネストしたコンポーネント**](https://github.com/yewstack/yew/tree/v0.16.0/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/more/css.mdx",
    "content": "---\ntitle: CSS\n---\n\n# CSS\n\n&lt;TODO&gt;\n\n統合的な CSS サポートについての提案はこちらにあります: [https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n## スタイルフレームワーク:\n\n今のところ、コミュニティメンバーは以下のスタイルフレームワークを開発しています。\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - JavaScript に依存しない Yew のスタイルフレームワーク\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - マテリアルデザインのコンポーネント\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI の CSS コンポーネント\n- [Yewtify](https://github.com/yewstack/yewtify) – Yew で Vuetify フレームワークで提供されている機能の実装\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/more/debugging.mdx",
    "content": "---\ntitle: Debugging\n---\n\n# デバッグ\n\n## パニック\n\nRust シンボルで良いスタックトレースをするには\n[`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook)クレートを使用してください。\n注意として、`cargo-web`でビルドされたものとは互換性がありません。\n\n## コンソールでのログ\n\n一般的に、Wasm の Web アプリはブラウザの API と連携することができ、`console.log`の API も例外ではありません。\nいつくかの選択肢があります:\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\nこのクレートは Rust の`log`クレートと親和性があります。\n\n```rust\n// セットアップ\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n}\n\n// 使用方法\nlog::info!(\"Update: {:?}\", msg);\n```\n\n### [`ConsoleService`](https://docs.rs/yew/latest/yew/services/console/struct.ConsoleService.html)\n\nこのサービスは Yew に含まれており、`\"services\"`の機能が有効化されている場合は利用可能です。\n\n```rust\n// 使用方法\nConsoleService::info(format!(\"Update: {:?}\", msg).as_ref());\n```\n\n## ソースマップ\n\n今のところは Rust/Wasm の Web アプリにはソースマップへの第一級のサポートがありません。\nもちろん、これは変更される可能性があります。これが当てはまらない場合、または進捗が見られる場合は、変更を提案してください！\n\n### 最新情報\n\n\\[2019 年 12 月\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> やらなければいけないことがまだたくさんあります。例えばツール側では Emscripten\\(Binaryen\\)と wasm-pack\\(wasm-bindgen\\)がそれらが実行する変換に関する DWARF 情報の更新をまだサポートしていません。\n\n\\[2020\\] [Rust Wasm デバッグガイド](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 残念なことに、WebAssembly のデバッグの物語はまだ未成熟です。ほとんどの Unix のシステムでは[DWARF](http://dwarfstd.org/)は実行中のプログラムをソースレベルで検査するためにデバッガに必要な情報をエンコードするために使用されます。Windows には同様の情報をエンコードする代替形式があります。現在、WebAssembly に相当するものはありません。\n\n\\[2019\\] [Rust Wasm ロードマップ](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> デバッグはトリッキーです。なぜなら、多くの話はこの活動チームの手の届かないところにあり、WebAssembly の標準化団体とブラウザ開発者ツールを実装している人たちの両方に依存しているからです。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/more/roadmap.mdx",
    "content": "---\ntitle: Roadmap\ndescription: The planned feature roadmap for the Yew framework\n---\n\n# ロードマップ\n\n## 優先順位\n\nフレームワークの今後の機能やフォーカスの優先順位は、コミュニティによって決定されます。2020 年の春には、プロジェクトの方向性についてのフィードバックを集めるために開発者アンケートが行われました。その概要は [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) で見ることができます。\n\n:::note\n主要な取り組みの状況は、Yew の Github の[Project board](https://github.com/yewstack/yew/projects)で確認できます。\n:::\n\n## 焦点\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Top Requested Features\n\n1. [関数型コンポーネント](https://github.com/yewstack/yew/projects/3)\n2. [Component ライブラリ](https://github.com/yewstack/yew/projects/4)\n3. より良い状態管理\n4. [サーバーサイドでのレンダリング](https://github.com/yewstack/yew/projects/5)\n\n### Production Readiness\n\n- テストカバレッジの向上\n- バイナリサイズ\n- [ベンチマークのパフォーマンス](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- チュートリアルを作る\n- プロジェクトのセットアップをシンプルにする\n\n### Pain Points\n\n- [Component のボイラープレート](https://github.com/yewstack/yew/issues/830)\n- Fetch API\n- [エージェント](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21/more/testing.mdx",
    "content": "---\ntitle: Testing apps\ndescription: Testing your app\n---\n\n# Testing\n\n&lt;TODO&gt;\n\n## wasm_bindgen_test\n\nRust Wasm ワーキンググループは wasm_bindgen_test というフレームワークをメンテナンスしており、組み込みの #[test] プロシージャルマクロの動作と同様の方法でブラウザでテストを実行することができます。詳細は、[Rust Wasm 活動グループのドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)に記載されています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.21.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.21\",\n    \"description\": \"The label for version 0.21\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Using Basic Web Technologies In Yew\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew's Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may needin one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/children.mdx",
    "content": "---\ntitle: '子コンポーネント'\n---\n\n:::caution\n\n`Children` をチェックおよび操作すると、アプリケーションで驚くべきかつ説明が難しい動作が発生することがよくあります。これにより、エッジケースが発生し、通常は予期しない結果が生じる可能性があります。`Children` を操作しようとする場合は、他の方法を検討する必要があります。\n\nYew は、子コンポーネントのプロパティの型として `Html` を使用することをサポートしています。`Children` または `ChildrenRenderer` が必要ない場合は、子コンポーネントとして `Html` を使用することをお勧めします。これは `Children` の欠点がなく、パフォーマンスのオーバーヘッドも低くなります。\n\n:::\n\n## 一般的な使用法\n\n_ほとんどの場合、_ コンポーネントに子コンポーネントを持たせる場合、子コンポーネントの型を気にする必要はありません。この場合、以下の例で十分です。\n\n````rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n\n## 高度な使用法\n\n### 型指定された子コンポーネント\n\n特定のタイプのコンポーネントを子コンポーネントとして渡したい場合は、`yew::html::ChildrenWithProps<T>` を使用できます。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n````\n\n## プロパティを持つネストされた子コンポーネント\n\nコンポーネントがその子コンポーネントを型指定している場合、ネストされたコンポーネントのプロパティにアクセスして変更することができます。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 列挙型の子コンポーネント\n\nもちろん、時には子コンポーネントをいくつかの異なるコンポーネントに制限する必要がある場合があります。そのような場合には、Yewについてさらに深く理解する必要があります。\n\nここでは、より良いエルゴノミクスを提供するために [`derive_more`](https://github.com/JelteF/derive_more) を使用しています。使用したくない場合は、各バリアントに対して手動で `From` を実装することができます。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 現在、`Into<Html>` を実装して、yew が `Item` をどのようにレンダリングするかを知ることができるようにします。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### オプションの型の子コンポーネント\n\n特定の型の単一のオプションの子コンポーネントを持つこともできます：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... ページ内容\n            </div>\n        }\n    }\n}\n\n// ページコンポーネントはサイドバーを含むかどうかを選択できます：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // サイドバーを含むページ\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // サイドバーを含まないページ\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## さらに読む\n\n- このパターンの実際の例については、yew-router のソースコードを参照してください。より高度な例については、yew リポジトリの[関連する例のリスト](https://github.com/yewstack/yew/tree/master/examples/nested_list)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '仕組み'\ndescription: 'フレームワークの低レベルの詳細について'\n---\n\n# 基本ライブラリの内部詳細\n\n## `html!` マクロの内部\n\n`html!` マクロは、HTMLに似たカスタム構文で記述されたコードを有効なRustコードに変換します。このマクロを使用することはYewアプリケーションの開発に必須ではありませんが、推奨されています。このマクロが生成するコードはYewのパブリックライブラリAPIを使用しており、希望すれば直接使用することもできます。いくつかのメソッドは意図的に文書化されていないため、誤用を避けるために注意が必要です。`yew-macro`の各更新により、生成されるコードはより効率的になり、`html!`構文をほとんど（または全く）変更することなく破壊的な変更を処理できるようになります。\n\n`html!` マクロを使用すると、宣言的なスタイルでコードを記述できるため、UIレイアウトコードはページのHTMLに非常に似たものになります。アプリケーションがよりインタラクティブになり、コードベースが大きくなるにつれて、この方法はますます有用になります。DOM 操作のすべてのコードを手動で記述するのに比べて、マクロがこれらすべてを処理してくれます。\n\n`html!` マクロの使用は非常に魔法のように感じるかもしれませんが、隠すべきものは何もありません。その仕組みに興味がある場合は、プログラム内の `html!` マクロ呼び出しを展開してみてください。`cargo expand` という便利なコマンドがあり、Rustマクロの展開を確認できます。`cargo expand` はデフォルトで `cargo` に含まれていないため、まだインストールしていない場合は `cargo install cargo-expand` を使用してインストールする必要があります。[Rust-Analyzer](https://rust-analyzer.github.io/) も[IDEからマクロ出力を取得するメカニズム](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)を提供しています。\n\n`html!` マクロの出力は通常非常に簡潔です！これは特徴です：機械生成のコードは時々アプリケーション内の他のコードと衝突することがあります。問題を防ぐために、`proc_macro` は「衛生」ルールに従っています。いくつかの例を以下に示します：\n\n1. Yewパッケージを正しく参照するために、マクロ生成コードでは `::yew::<module>` を使用し、直接 `yew::<module>` を使用しません。これは `::alloc::vec::Vec::new()` を呼び出すのと同じ理由です。\n2. トレイトメソッド名の衝突を避けるために、`<Type as Trait>` を使用して正しいトレイトメンバーを使用していることを確認します。\n\n## 仮想 DOM とは？\n\nDOM（「ドキュメントオブジェクトモデル」）は、ブラウザによって管理されるHTMLコンテンツの表現です。「仮想」 DOM は、単にメモリ内の DOM のコピーです。仮想 DOM を管理することで、メモリのオーバーヘッドが増加しますが、ブラウザAPIの使用を回避または遅延させることでバッチ処理と高速な読み取りを実現できます。\n\nメモリ内に DOM のコピーを持つことは、宣言的UIを使用するライブラリの使用を促進するのに役立ちます。ユーザーイベントに基づいて DOM を変更するための特定のコードが必要な場合とは異なり、ライブラリは一般的な方法を使用して DOM の「差分」を行うことができます。Yewコンポーネントが更新され、そのレンダリング方法を変更したい場合、Yewライブラリは仮想 DOM の2番目のコピーを構築し、現在画面上に表示されている内容をミラーリングする仮想 DOM と直接比較します。両者の「差分」は増分更新に分解され、ブラウザAPIと共に適用されます。更新が適用されると、古い仮想 DOM のコピーは破棄され、新しいコピーが将来の差分チェックのために保存されます。\n\nこの「差分」アルゴリズムは、時間の経過とともに最適化され、複雑なアプリケーションのパフォーマンスを向上させることができます。YewアプリケーションはWebAssemblyを介して実行されるため、Yewは将来的により複雑なアルゴリズムを採用する上で競争力を持つと信じています。\n\nYewの仮想 DOM はブラウザの DOM と完全に一対一対応しているわけではありません。DOM 要素を整理するための「リスト」や「コンポーネント」も含まれています。リストは単に要素の順序付きリストである場合もありますが、より強力な場合もあります。各リスト要素に「キー」注釈を追加することで、アプリケーション開発者はリストが変更されたときに差分更新の計算に必要な作業量を最小限に抑えるための追加の最適化をYewに提供できます。同様に、コンポーネントは再レンダリングが必要かどうかを示すカスタムロジックを提供し、パフォーマンスを向上させるのに役立ちます。\n\n## Yewスケジューラとコンポーネントスコープのイベントループ\n\n_貢献ドキュメント - `yew::scheduler` と `yew::html::scope` の仕組みを詳しく説明_\n\n## さらなる読み物\n\n- [Rustのマクロに関する詳細情報](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` に関する詳細情報](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` のAPIドキュメント](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'イミュータブルタイプ'\ndescription: 'Yew のイミュータブルデータ構造'\n---\n\n## イミュータブルタイプとは？\n\nこれらのタイプは、インスタンス化はできるが値を変更することはできないタイプです。値を更新するには、新しい値をインスタンス化する必要があります。\n\n## なぜイミュータブルタイプを使用するのですか？\n\nReact と同様に、プロパティは祖先から子孫に伝播されます。これは、各コンポーネントが更新されるたびにプロパティが存在する必要があることを意味します。したがって、プロパティは理想的には簡単にクローンできるべきです。これを実現するために、通常は `Rc` にラップします。\n\nイミュータブルタイプは、コンポーネント間でプロパティの値を低コストでクローンできるため、プロパティの値を保持するのに最適です。\n\n## 一般的なイミュータブルタイプ\n\nYew は `implicit-clone` クレートから以下のイミュータブルタイプの使用を推奨しています：\n\n- `IString`（Yew では `AttrValue` としてエイリアス化）- `String` の代わりに文字列用\n- `IArray<T>` - `Vec<T>` の代わりに配列・ベクター用\n- `IMap<K, V>` - `HashMap<K, V>` の代わりにマップ用\n\nこれらのタイプは参照カウント（`Rc`）または静的参照のいずれかであり、非常に安価にクローンできます。\n\n## さらに読む\n\n- [イミュータブルの例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '最適化とベストプラクティス'\nsidebar_label: Optimizations\ndescription: 'アプリケーションのパフォーマンスを最適化する'\n---\n\n## スマートポインタの使用\n\n**注意：このセクションで使用されている用語に混乱がある場合は、Rustのマニュアルにある[スマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)が役立ちます。**\n\n再レンダリング時に大量のデータをクローンしてpropsを作成するのを避けるために、スマートポインタを使用してデータ自体ではなくデータへの参照のみをクローンすることができます。propsや子コンポーネントに関連データの参照を渡すことで、データを変更する必要がある子コンポーネントでデータをクローンするのを避けることができます。`Rc::make_mut`を使用してデータをクローンし、変更するための可変参照を取得できます。\n\nこれにより、`Component::changed`でのpropの変更がコンポーネントの再レンダリングを必要とするかどうかを判断する際にさらに利点があります。これは、データの値ではなくポインタのアドレス（つまり、データがマシンメモリに格納されている場所）を比較できるためです。2つのポインタが同じデータを指している場合、それらが指しているデータの値は同じでなければなりません。逆は必ずしも真ではないことに注意してください！2つのポインタアドレスが異なる場合でも、基になるデータは同じである可能性があります。この場合、基になるデータを比較する必要があります。\n\nこの比較を行うには、`PartialEq`（データを比較する際に自動的に使用される等価演算子`==`）ではなく、`Rc::ptr_eq`を使用する必要があります。Rustのドキュメントには、`Rc::ptr_eq`に関する[詳細](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)があります。\n\nこの最適化は、`Copy`を実装していないデータ型に最も有用です。データを安価にコピーできる場合、それをスマートポインタの後ろに置く必要はありません。`Vec`、`HashMap`、`String`などのデータ集約型の構造体に対して、スマートポインタを使用することでパフォーマンスの向上が見込まれます。\n\nこの最適化は、子コンポーネントが値を更新しない場合に最も効果的であり、親コンポーネントがほとんど更新されない場合にさらに効果的です。これにより、`Rc<_>`は純粋なコンポーネントでpropsの値をラップするのに適した選択肢となります。\n\nただし、子コンポーネントでデータを自分でクローンする必要がない限り、この最適化は無駄であり、不要な参照カウントのコストを追加するだけです。Yewのpropsはすでに参照カウントされており、内部でデータのクローンは行われません。\n\n## レンダリング関数\n\nコードの可読性のために、`html!`の一部の繰り返しコードを専用の分割関数に移行することは通常意味があります。これにより、コードが読みやすくなり、インデントが減り、良いデザインパターンを奨励します。特に、複数の場所で呼び出すことができるこれらの関数を使用して、コード量を減らすことができます。\n\n## 純粋なコンポーネント\n\n純粋なコンポーネントは、その状態を変更せず、コンテンツを表示し、メッセージを通常の可変コンポーネントに伝播するコンポーネントです。これらは、`html!`マクロ内でコンポーネント構文（`<SomePureComponent />`）を使用する点でビュー関数とは異なり、実装に応じてメモ化される可能性があります（これは、一度関数が呼び出されると、その値が「保存」されることを意味し、同じパラメータで複数回呼び出された場合、その値を再計算する必要がなく、最初の関数呼び出しから保存された値を返すだけです）。Yewは内部でpropsを比較するため、propsが変更された場合にのみUIを再レンダリングします。\n\n## ワークスペースを使用してコンパイル時間を短縮する\n\nYewの最大の欠点は、コンパイルにかかる時間が長いことです。プロジェクトのコンパイルにかかる時間は、`html!`マクロに渡されるコードの量に関連しているようです。小規模なプロジェクトでは問題にならないようですが、大規模なアプリケーションでは、コンパイラがアプリケーションのために行う作業量を最小限に抑えるためにコードを複数のクレートに分割することが理にかなっています。\n\n1つの方法として、メインクレートがルーティング/ページ選択を処理し、各ページごとに異なるクレートを作成することが考えられます。各ページは異なるコンポーネントまたは`Html`を生成する大きな関数である可能性があります。アプリケーションの異なる部分を含むクレート間で共有されるコードは、プロジェクトが依存する別のクレートに格納できます。理想的には、すべてのコードを再コンパイルするのではなく、メインクレートと1つのページクレートのみを再コンパイルすることになります。最悪の場合、「共通」クレートで何かを編集した場合、すべての依存コードを再コンパイルする必要があり、元の状態に戻ります。\n\nメインクレートが重すぎる場合や、深くネストされたページ（例：別のページ上にレンダリングされるページ）を迅速に反復したい場合は、メインページの簡略化された実装を作成し、作業中のコンポーネントを追加でレンダリングするためにサンプルクレートを使用できます。\n\n## バイナリサイズの縮小\n\n- Rustコードの最適化\n- `cargo.toml`（リリースプロファイルの定義）\n- `wasm-opt` を使用してwasmコードを最適化\n\n**注意：バイナリサイズの縮小に関する詳細は、[Rust Wasmマニュアル](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)を参照してください。**\n\n### Cargo.toml\n\nリリースビルドをより小さくするために、`Cargo.toml`の`[profile.release]`セクションで利用可能な設定を使用して構成できます。\n\n```toml, title=Cargo.toml\n[profile.release]\n# バイナリサイズを小さくする\npanic = 'abort'\n# コード全体を最適化する（最適化は良くなるが、ビルド速度は遅くなる）\ncodegen-units = 1\n# サイズを最適化する（より積極的なアプローチ）\nopt-level = 'z'\n# サイズを最適化する\n# opt-level = 's'\n# プログラム全体の解析を使用してリンク時に最適化\nlto = true\n```\n\n### 開発版 Cargo 設定\n\nRust と cargo の実験的な開発版機能から追加の利点を得ることもできます。`trunk` の開発版ツールチェーンを使用するには、`RUSTUP_TOOLCHAIN=\"nightly\"` 環境変数を設定します。その後、`.cargo/config.toml` で不安定な rustc 機能を構成できます。不安定機能のドキュメント、特に[`build-std`]および[`build-std-features`]に関する部分を参照して、設定方法を確認してください。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# rust-srcコンポーネントが必要です。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不安定な機能のリスト]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n開発版のRustコンパイラには、[この例](https://github.com/yewstack/yew/issues/2696)のようなバグが含まれている可能性があるため、定期的に監視し調整する必要があります。これらの実験的なオプションを使用する際は注意が必要です。\n:::\n\n### wasm-opt\n\nさらに、`wasm` コードのサイズを最適化することができます。\n\nRust Wasm マニュアルには、Wasm バイナリファイルのサイズを縮小する方法に関するセクションがあります：[.wasm サイズの縮小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- `wasm-pack` を使用すると、デフォルトでリリースビルドの `wasm` コードが最適化されます\n- `wasm` ファイルに直接 `wasm-opt` を使用する\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### yew/examples/ の 'minimal' サンプルのビルドサイズ\n\n注意：`wasm-pack` は Rust と Wasm コードの最適化を組み合わせています。この例では、`wasm-bindgen` は Rust のサイズ最適化を行っていません。\n\n| ツールチェーン              | サイズ |\n| :-------------------------- | :----- |\n| wasm-bindgen                | 158KB  |\n| wasm-bindgen + wasm-opt -Os | 116KB  |\n| wasm-pack                   | 99 KB  |\n\n## さらに読む\n\n- [Rust マニュアルのスマート ポインターに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm マニュアルのコードサイズの縮小に関する章](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust プロファイルに関するドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'ポータル (Portals)'\ndescription: 'コンテンツをDOMツリー外のノードにレンダリングする'\n---\n\n## ポータルとは？\n\nポータル (Portal) は、子要素を親コンポーネントのDOM階層外のDOMノードにレンダリングする方法を提供します。`yew::create_portal(child, host)` は `Html` 値を返し、`child` を `host` 要素の子要素としてレンダリングしますが、親コンポーネントの階層下ではありません。\n\n## 使用方法\n\nポータルの典型的な用途には、モーダルダイアログやホバーカード、さらに技術的な用途として、要素の [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) の内容を制御すること、スタイルシートを周囲のドキュメントの `<head>` に添付すること、`<svg>` の中央の `<defs>` 要素に参照される要素を収集することなどがあります。\n\n`yew::create_portal` は低レベルの構成要素であることに注意してください。ライブラリはこれを使用してより高レベルのAPIを実装し、その後アプリケーションはこれらのAPIを使用できます。例えば、ここでは `children` を `yew` 以外の要素にレンダリングするシンプルなモーダルダイアログを示します。この要素は `id=\"modal_host\"` で識別されます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## イベント処理\n\nポータル内部の要素で発生するイベントは、仮想DOMのバブリングに従います。つまり、ポータルが要素の子要素としてレンダリングされる場合、その要素上のイベントリスナーは、ポータル内部から発生するイベントをキャプチャします。たとえポータルが実際のDOM内の無関係な位置にその内容をレンダリングしていてもです。\n\nこれにより、開発者は使用しているコンポーネントがポータルを使用して実装されているかどうかを気にする必要がなくなります。いずれにせよ、その子要素上で発生するイベントはバブリングします。\n\n既知の問題として、ポータルから **閉じた** シャドウルートへのイベントは2回分配されます。1回はシャドウルート内部の要素に対して、もう1回はホスト要素自体に対してです。**開いた** シャドウルートは正常に動作しますので、これが影響する場合は、いつでもバグレポートを提出してください。\n\n## さらなる読み物\n\n- [ポータルの例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: 'サーバーサイドレンダリング'\ndescription: 'Yewコンポーネントをサーバーサイドでレンダリングする。'\n---\n\n# サーバーサイドレンダリング (Server-Side Rendering)\n\nデフォルトでは、Yewコンポーネントはクライアントサイドでレンダリングされます。ユーザーがウェブサイトにアクセスすると、サーバーは実際のコンテンツを含まない骨組みのHTMLファイルとWebAssemblyパッケージをブラウザに送信します。すべてのコンテンツはクライアントサイドでWebAssemblyパッケージによってレンダリングされます。これをクライアントサイドレンダリングと呼びます。\n\nこの方法はほとんどのウェブサイトにとって有効ですが、いくつかの注意点があります：\n\n1. ユーザーはWebAssemblyパッケージがダウンロードされ、初期レンダリングが完了するまで何も表示されません。これにより、ネットワークが遅い場合にユーザーエクスペリエンスが悪化する可能性があります。\n2. 一部の検索エンジンは動的にレンダリングされたウェブページのコンテンツをサポートしておらず、サポートしている検索エンジンでも通常は動的なウェブサイトのランキングが低くなります。\n\nこれらの問題を解決するために、ウェブサイトをサーバーサイドでレンダリングすることができます。\n\n## 動作原理\n\nYewはページをサーバーサイドでレンダリングするための `ServerRenderer` を提供しています。\n\nYewコンポーネントをサーバーサイドでレンダリングするには、`ServerRenderer::<App>::new()` を使用してレンダラーを作成し、`renderer.render().await` を呼び出して `<App />` を `String` としてレンダリングします。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// この例が CI の WASM 環境で動作することを保証するために `flavor = \"current_thread\"` を使用しています。\n// マルチスレッドを使用したい場合は、デフォルトの `#[tokio::main]` マクロを使用できます。\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // プリント: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## コンポーネントのライフサイクル\n\nクライアントサイドレンダリングとは異なり、サーバーサイドレンダリング時のコンポーネントのライフサイクルは異なります。\n\nコンポーネントが最初に `Html` として正常にレンダリングされるまで、`use_effect`（および `use_effect_with`）以外のすべてのフックは正常に動作します。\n\n:::caution ブラウザインターフェースは利用できません！\n\n`web_sys` などのブラウザ関連のインターフェースは、サーバーサイドレンダリング時には利用できません。これらを使用しようとすると、アプリケーションがクラッシュします。このロジックは `use_effect` または `use_effect_with` に隔離する必要があります。これらはサーバーサイドレンダリング時には実行されないためです。\n\n:::\n\n:::danger 構造化コンポーネント\n\nサーバーサイドレンダリング時に構造化コンポーネントを使用することは可能ですが、クライアントサイドの安全なロジック（関数コンポーネントの `use_effect` フックなど）とライフサイクルイベントの間には明確な境界がなく、ライフサイクルイベントの呼び出し順序もクライアントとは異なります。\n\nさらに、構造化コンポーネントは、すべての子コンポーネントがレンダリングされ `destroy` メソッドが呼び出されるまでメッセージを受け取り続けます。開発者は、コンポーネントに渡される可能性のあるメッセージがブラウザインターフェースを呼び出すロジックにリンクされないようにする必要があります。\n\nサーバーサイドレンダリングをサポートするアプリケーションを設計する際は、特別な理由がない限り、関数コンポーネントを使用することをお勧めします。\n\n:::\n\n## サーバーサイドレンダリング中のデータ取得\n\nデータ取得はサーバーサイドレンダリングとハイドレーション（hydration）中の難点の一つです。\n\n従来の方法では、コンポーネントがレンダリングされるとすぐに利用可能になります（仮想DOMを出力してレンダリングします）。コンポーネントがデータを取得する必要がない場合、この方法は有効です。しかし、コンポーネントがレンダリング時にデータを取得しようとするとどうなるでしょうか？\n\n以前は、Yewにはコンポーネントがまだデータを取得しているかどうかを検出するメカニズムがありませんでした。データ取得クライアントは、初期レンダリング中に何が要求されたかを検出し、要求が完了した後に再レンダリングをトリガーするソリューションを実装する責任がありました。サーバーはこのプロセスを繰り返し、応答を返す前にレンダリング中に追加の保留中の要求がないことを確認します。\n\nこれは、コンポーネントを繰り返しレンダリングするため、CPUリソースを浪費するだけでなく、データクライアントは、サーバー側で取得したデータをハイドレーション中に利用可能にする方法を提供する必要があり、初期レンダリングで返される仮想DOMがサーバーサイドレンダリングのDOMツリーと一致することを保証する必要があります。これは実現が難しい場合があります。\n\nYewは、`<Suspense />` を使用してこの問題を解決する異なるアプローチを採用しています。\n\n`<Suspense />` は特別なコンポーネントで、クライアント側で使用する場合、コンポーネントがデータを取得（保留）している間にフォールバックUIを表示し、データ取得が完了した後に通常のUIに戻る方法を提供します。\n\nアプリケーションがサーバーサイドレンダリングされると、Yewはコンポーネントが保留状態でなくなるまで待機し、それを文字列バッファにシリアル化します。\n\nハイドレーション中、`<Suspense />` コンポーネント内の要素は、すべての子コンポーネントが保留状態でなくなるまでハイドレーションされません。\n\nこの方法により、開発者はサーバーサイドレンダリングに対応したクライアント非依存のアプリケーションを簡単に構築し、データ取得を行うことができます。\n\n## `<head>` タグのレンダリング\n\nSSR でよく必要とされるのは、クローラーやソーシャルプレビューが最初のロード時に正しいメタデータを参照できるよう、動的な `<head>` コンテンツ（`<title>`、`<meta>` など）をレンダリングすることです。\n\n`ServerRenderer` はコンポーネントツリー（通常はドキュメントの body 部分）のみをレンダリングし、`<head>` にはアクセスできません。そのため、head タグは **Yew の外部でサーバー側に**生成し、クライアントに送信する前に HTML テンプレートに埋め込む必要があります。\n\n[`ssr_router` サンプル](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) はこのパターンを示しています：サーバーはリクエスト URL からルートを判別し、適切な `<title>` および `<meta>` タグを生成して、Trunk が生成した `index.html` の `</head>` の前に挿入します。\n\n:::info\n\n完全に SSR 互換のサードパーティソリューションとして、[Bounce の `<Helmet/>` コンポーネント](https://docs.rs/bounce/latest/bounce/helmet/index.html) が利用できます。\n\n:::\n\n## SSR ハイドレーション\n\n## サーバーサイドレンダリングハイドレーション（SSR Hydration）\n\nハイドレーションは、Yewアプリケーションをサーバー側で生成されたHTMLファイルに接続するプロセスです。デフォルトでは、`ServerRender` はハイドレーション可能なHTML文字列を出力し、追加情報を含んでハイドレーションを容易にします。`Renderer::hydrate` メソッドを呼び出すと、Yewは最初からレンダリングするのではなく、アプリケーションが生成した仮想DOMとサーバーレンダラーが生成したHTML文字列を調整します。\n\n:::caution\n\n`ServerRenderer` が作成したHTMLマークアップを正常にハイドレーションするためには、クライアントはSSRに使用されたレイアウトと完全に一致する仮想DOMレイアウトを生成する必要があります。要素を含まないコンポーネントも含めてです。特定の実装でのみ使用されるコンポーネントがある場合は、`PhantomComponent` を使用して追加のコンポーネントの位置を埋めることを検討してください。\n:::\n\n:::warning\n\nSSR出力（静的HTML）をブラウザが初期レンダリングした後、実際のDOMが期待されるDOMと一致する場合にのみ、ハイドレーションは成功します。HTMLが規格に準拠していない場合、ハイドレーションは失敗する可能性があります。ブラウザは不正なHTMLのDOM構造を変更する可能性があり、実際のDOMが期待されるDOMと異なることがあります。例えば、[`<tbody>` のない `<table>` がある場合、ブラウザはDOMに `<tbody>` を追加する可能性があります](https://github.com/yewstack/yew/issues/2684)。\n:::\n\n## ハイドレーション中のコンポーネントライフサイクル\n\nハイドレーション中、コンポーネントは作成後に2回連続してレンダリングされます。すべてのエフェクトは2回目のレンダリングが完了した後に呼び出されます。コンポーネントのレンダリング関数に副作用がないことを確認することが重要です。状態を変更したり、追加のレンダリングをトリガーしたりしないようにしてください。現在、状態を変更したり追加のレンダリングをトリガーしたりするコンポーネントがある場合は、それらを `use_effect` フックに移動してください。\n\nハイドレーション中、構造化コンポーネントを使用してサーバーサイドレンダリングを行うことができます。ビュー関数はレンダリング関数の前に複数回呼び出されます。レンダリング関数が呼び出されるまで、DOMは未接続と見なされ、`rendered()` メソッドが呼び出される前にレンダリングノードにアクセスすることを防ぐ必要があります。\n\n## 例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // body 要素の下のすべてのコンテンツをハイドレーションし、末尾の要素を削除します（存在する場合）。\n    renderer.hydrate();\n}\n```\n\n例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## シングルスレッドモード\n\nYewは `yew::LocalServerRenderer` を使用してシングルスレッドでのサーバーサイドレンダリングをサポートしています。このモードはWASIのようなシングルスレッド環境に適しています。\n\n```rust\n// `wasm32-wasip1` または `wasm32-wasip2` ターゲットを使用してビルドしてください。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n`wasm32-unknown-unknown` ターゲットを使用してSSRアプリケーションをビルドする場合、`not_browser_env` 機能フラグを使用して、Yew内部のブラウザ固有のAPIへのアクセスを無効にすることができます。これは、Cloudflare Workerのようなサーバーレスプラットフォームで非常に便利です。\n:::\n\n:::caution\n\nサーバーサイドレンダリングは現在実験的な機能です。バグを見つけた場合は、[GitHubで報告してください](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'コールバック関数 (Callbacks)'\n---\n\n## コールバック関数 (Callbacks)\n\nコールバック関数は、Yew でサービス、エージェント、および親コンポーネントと通信するために使用されます。内部的には、それらの型は `Rc` に包まれた `Fn` に過ぎず、クローンを許可します。\n\nそれらには `emit` 関数があり、その `<IN>` 型を引数として取り、それをターゲットが期待するメッセージに変換します。親コンポーネントのコールバック関数が子コンポーネントに props として提供される場合、子コンポーネントはその `update` ライフサイクルフックでコールバック関数の `emit` 関数を呼び出して、メッセージを親コンポーネントに送信できます。`html!` マクロで props として提供されるクロージャまたは関数は、自動的にコールバック関数に変換されます。\n\nシンプルなコールバック関数の使用例は次のようになります：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nこの関数を `callback` に渡す場合、常に1つの引数を持つ必要があります。例えば、`onclick` ハンドラは `MouseEvent` 型の引数を受け取る関数である必要があります。その後、ハンドラはコンポーネントにどのタイプのメッセージを送信するかを決定できます。このメッセージは無条件に次の更新サイクルにスケジュールされます。\n\n更新を引き起こす必要がないコールバック関数が必要な場合は、`batch_callback` を使用してください。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 関連例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高階コンポーネント'\n---\n\nいくつかの状況では、構造コンポーネントは特定の機能（例えば Suspense）を直接サポートしていないか、または特定の機能を使用するために大量のボイラープレートコードが必要です（例えば Context）。\n\nこのような場合、高階コンポーネントの関数コンポーネントを作成することをお勧めします。\n\n## 高階コンポーネントの定義\n\n高階コンポーネントは、新しい HTML を追加せず、他のコンポーネントをラップして追加機能を提供するコンポーネントです。\n\n### 例\n\nContext（コンテキスト）フックを使用し、それを構造コンポーネントに渡す例\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '紹介'\ndescription: 'Yew のコンポーネント'\n---\n\n## コンポーネントとは？\n\nコンポーネントは Yew の構成要素です。内部状態を管理し、要素を DOM にレンダリングできます。`Component` トレイトを実装することでコンポーネントを作成します。\n\n## コンポーネントマークアップの作成\n\nYew は仮想 DOM を使用して要素を DOM にレンダリングします。仮想 DOM ツリーは `html!` マクロを使用して構築できます。`html!` の構文は HTML に似ていますが、同じではありません。ルールもより厳格です。また、条件付きレンダリングやイテレータを使用したリストのレンダリングなどの強力な機能も提供します。\n\n:::info\n[`html!` マクロ、その使用方法、および構文についてさらに詳しく知る](concepts/html/introduction.mdx)\n:::\n\n## コンポーネントにデータを渡す\n\nYew コンポーネントは _props_ を使用して親コンポーネントと子コンポーネント間で通信します。親コンポーネントは任意のデータを props として子コンポーネントに渡すことができます。Props は HTML 属性に似ていますが、任意の Rust 型を props として渡すことができます。\n\n:::info\n[props についてさらに詳しく知る](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n親/子通信以外の通信には、[コンテキスト](../../concepts/contexts.mdx) を使用してください\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'ライフサイクル'\ndescription: 'コンポーネントとそのライフサイクルフック'\n---\n\n`Component` トレイトには、実装する必要がある多くのメソッドがあります。Yew はコンポーネントのライフサイクルのさまざまな段階でこれらのメソッドを呼び出します。\n\n## ライフサイクル\n\n:::important ドキュメントの改善\n`ドキュメントに貢献する：` [カスタムライフサイクルを持つコンポーネントの例を追加](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## ライフサイクルメソッド\n\n### Create\n\nコンポーネントが作成されるとき、それは親コンポーネントからプロパティを受け取り、それらは `create` メソッドに渡される `Context<Self>` に保存されます。これらのプロパティはコンポーネントの状態を初期化するために使用でき、\"link\" はコールバックを登録したり、コンポーネントにメッセージを送信したりするために使用できます。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体的な実装\n        }\n    }\n}\n```\n\n### View\n\n`view` メソッドは、コンポーネントがDOMにどのようにレンダリングされるべきかを記述することを可能にします。Rust関数を使用してHTMLに似たコードを書くことは非常に混乱する可能性があるため、Yewは`html!`マクロを提供しています。これにより、HTMLおよびSVGノードを宣言し（およびそれらに属性とイベントリスナーを追加し）、子コンポーネントを便利にレンダリングする方法が提供されます。このマクロは、ReactのJSXに似ています（プログラミング言語の違いを除いて）。一つの違いは、YewがSvelteのようなプロパティの簡略化された構文を提供している点です。ここでは、`{onclick}`とだけ書くことができ、`onclick={onclick}`と書く必要はありません。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n使用方法の詳細については、[html! ガイド](concepts/html/introduction.mdx) を参照してください。\n\n### Rendered\n\n`rendered` コンポーネントライフサイクルメソッドは、`view` が呼び出され、Yew がその結果を DOM にレンダリングした後、ブラウザがページを更新する前に呼び出されます。このメソッドは、コンポーネントが要素をレンダリングした後にのみ完了できる操作を実行したい場合に非常に便利です。また、`first_render` という名前のパラメーターがあり、この関数が最初のレンダリング時に呼び出されたか、後続のレンダリング時に呼び出されたかを判断するために使用できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nこのライフサイクルメソッドは実装する必要はなく、デフォルトでは何も実行しません。\n:::\n\n### Update\n\nコンポーネントとの通信は主にメッセージを通じて行われ、これらのメッセージは `update` ライフサイクルメソッドによって処理されます。これにより、コンポーネントはメッセージに基づいて自身を更新し、再レンダリングが必要かどうかを判断できます。メッセージはイベントリスナー、子コンポーネント、エージェント、サービス、またはフューチャーによって送信されることがあります。\n\n以下は `update` の実装例です：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 再レンダリング\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体的な実装\n        }\n    }\n\n}\n```\n\n### Changed\n\nコンポーネントは親コンポーネントによって再レンダリングされることがあります。この場合、新しいプロパティを受け取り、再レンダリングが必要になることがあります。この設計により、プロパティの値を変更するだけで親子コンポーネント間の通信が促進されます。プロパティが変更されると、デフォルトの実装によりコンポーネントが再レンダリングされます。\n\n### Destroy\n\nコンポーネントがDOMからアンマウントされると、Yewは`destroy`ライフサイクルメソッドを呼び出します。コンポーネントが破棄される前にクリーンアップ操作を実行する必要がある場合に便利です。このメソッドはオプションであり、デフォルトでは何も実行しません。\n\n### 無限ループ\n\nYewのライフサイクルメソッドでは無限ループが発生する可能性がありますが、それは各レンダリング後に同じコンポーネントを更新し、その更新が再レンダリングを要求する場合にのみ発生します。\n\n以下は簡単な例です：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // どのメッセージでも常に再レンダリングを要求します\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // レンダリングする内容は重要ではありません\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // この新しいメッセージを使用してコンポーネントを更新するように要求します\n        ctx.link().send_message(());\n    }\n}\n```\n\nここで何が起こっているのか見てみましょう：\n\n1. `create` 関数を使用してコンポーネントを作成します。\n2. `view` メソッドを呼び出して、Yew がブラウザの DOM にレンダリングする内容を知ることができます。\n3. `rendered` メソッドを呼び出し、`Context` リンクを使用して更新メッセージをスケジュールします。\n4. Yew がレンダリングフェーズを完了します。\n5. Yew はスケジュールされたイベントをチェックし、更新メッセージキューが空でないことを確認してメッセージを処理します。\n6. `update` メソッドを呼び出し、変更が発生し、コンポーネントが再レンダリングする必要があることを示す `true` を返します。\n7. ステップ2に戻ります。\n\n`rendered` メソッドで更新をスケジュールすることは依然として可能であり、これは通常便利ですが、その際にはこのループをどのように終了させるかを考慮してください。\n\n## 関連タイプ\n\n`Component` トレイトには、`Message` と `Properties` の2つの関連タイプがあります。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` タイプは、イベントが発生した後にコンポーネントにメッセージを送信するために使用されます。例えば、ユーザーがボタンをクリックしたり、ページをスクロールしたりしたときに何かを実行したい場合があります。コンポーネントは通常、複数のイベントに応答する必要があるため、`Message` タイプは通常、処理するイベントごとにバリアントを持つ列挙型です。\n\nコードベースを整理する際には、`Message` タイプの定義をコンポーネントを定義する同じモジュールに含めるのが賢明です。メッセージタイプの命名に一貫した命名規則を採用することが役立つ場合があります。一つのオプション（唯一のオプションではありませんが）は、タイプを `ComponentNameMsg` と命名することです。例えば、コンポーネントが `Homepage` と名付けられている場合、タイプを `HomepageMsg` と命名することができます。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` は、親コンポーネントからコンポーネントに渡される情報を表します。この型は `Properties` トレイトを実装する必要があり（通常はそれを派生させる）、特定のプロパティが必須かオプションかを指定できます。コンポーネントの作成および更新時にこの型が使用されます。コンポーネントのモジュール内で `Props` という名前の構造体を作成し、それをコンポーネントの `Properties` 型として使用するのが一般的な方法です。通常、\"properties\" は \"props\" と略されます。プロパティは親コンポーネントから渡されるため、アプリケーションのルートコンポーネントは通常、`Properties` 型として `()` を持ちます。ルートコンポーネントにプロパティを指定する場合は、`App::mount_with_props` メソッドを使用します。\n\n:::info\n[プロパティに関する詳細はこちら](./properties)\n:::\n\n## ライフサイクルコンテキスト\n\nすべてのコンポーネントライフサイクルメソッドは、コンテキストオブジェクトを受け取ります。このオブジェクトは、コンポーネントのスコープへの参照を提供し、コンポーネントにメッセージを送信したり、コンポーネントに渡されたプロパティを取得したりすることができます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Props)'\ndescription: '親子コンポーネント間の通信'\n---\n\nプロパティ (Properties) は、子コンポーネントと親コンポーネントの間で通信を可能にします。各コンポーネントには、親コンポーネントから渡される内容を記述するための関連プロパティ型があります。理論的には、これは `Properties` トレイトを実装した任意の型である可能性がありますが、実際には、各フィールドがプロパティを表す構造体であるべきです。\n\n## 派生マクロ\n\n`Properties` トレイトを自分で実装する必要はありません。`#[derive(Properties)]` を使用して実装を自動生成できます。`Properties` を派生する型は `PartialEq` も実装する必要があります。\n\n### フィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。以下の属性を使用すると、他の値が設定されていない限り、プロパティに初期値を提供できます。\n\n:::tip\nプロパティは Rustdoc によって生成されたドキュメントには表示されません。プロパティのドキュメント文字列には、そのプロパティがオプションであるかどうか、または特別なデフォルト値があるかどうかを記載する必要があります。\n:::\n\n#### `#[prop_or_default]`\n\nフィールド型のデフォルト値を使用してプロパティ値を初期化します。これは `Default` トレイトを使用します。\n\n#### `#[prop_or(value)]`\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。\n\n#### `#[prop_or_else(function)]`\n\n`function` を呼び出してプロパティ値を初期化します。`function` は `FnMut() -> T` のシグネチャを持つ必要があります。ここで、`T` はフィールド型です。\n\n## `PartialEq`\n\n`Properties` は `PartialEq` を実装する必要があります。これにより、Yew はそれらを比較し、変更があった場合に `changed` メソッドを呼び出すことができます。\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたポインタに基づいて格納されます。これにより、コンポーネントツリーに渡されるプロパティにはポインタのみが渡され、プロパティ全体をクローンすることによる高価なパフォーマンスオーバーヘッドを回避できます。\n\n:::tip\n`AttrValue` を使用してください。これは、クローンが必要な String やその他の類似の型を使用せずに済むようにするために提供されているカスタムプロパティ値型です。\n:::\n\n## 例\n\n```rust\nuse yew::Properties;\n/// virtual_dom から AttrValue をインポート\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// リンクにはターゲットが必要です\n    href: AttrValue,\n    /// また、String ではなく AttrValue を使用していることに注意してください\n    text: AttrValue,\n    /// リンクの色、デフォルトは `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 値が None の場合、ビュー関数はサイズを指定しません\n    #[prop_or_default]\n    size: Option<u32>,\n    /// ビュー関数がアクティブを指定しない場合、デフォルトは true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、属性や基本式 (`Foo { ..base }`) を使用することはできません。型パスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// リンクにはターゲットが必要です\n    href: AttrValue,\n    /// また、String ではなく AttrValue を使用していることに注意してください\n    text: AttrValue,\n    /// リンクの色、デフォルトは `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 値が None の場合、ビュー関数はサイズを指定しません\n    #[prop_or_default]\n    size: Option<u32>,\n    /// ビュー関数がアクティブを指定しない場合、デフォルトは true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// この関数は href と text を String として受け取ります\n    /// `AttrValue::from` を使用してそれらを `AttrValue` に変換できます\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '参照 (Refs)'\ndescription: 'DOM への越境アクセスを実現する'\n---\n\n`ref` キーワードは、任意の HTML 要素やコンポーネントに使用して、その要素に付随する DOM `Element` を取得できます。これにより、`view` ライフサイクルメソッドの外で DOM を変更することができます。\n\nこれは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。例えば、コンポーネントの `rendered` メソッドで `NodeRef` を使用すると、`view` からレンダリングされた後に canvas 要素に描画呼び出しを行うことができます。\n\n構文は次のとおりです：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 関連例\n\n- [ノード参照](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'スコープ'\ndescription: 'コンポーネントのスコープ'\n---\n\n## コンポーネントの `Scope<_>` インターフェース\n\n`Scope` は、メッセージを介してコールバックを作成し、自身を更新するメカニズムです。コンポーネントに渡されるコンテキストオブジェクトで `link()` を呼び出すことで、その参照を取得します。\n\n### `send_message`\n\nこの関数は、コンポーネントにメッセージを送信できます。メッセージは `update` メソッドによって処理され、コンポーネントが再レンダリングするかどうかを決定します。\n\n### `send_message_batch`\n\nこの関数は、コンポーネントに複数のメッセージを同時に送信できます。これは `send_message` に似ていますが、任意のメッセージが `update` メソッドで `true` を返す場合、バッチ内のすべてのメッセージの処理が完了した後にコンポーネントが再レンダリングされます。\n\n指定された引数ベクターが空の場合、この関数は何も実行しません。\n\n### `callback`\n\nコールバックを作成し、実行時にコンポーネントにメッセージを送信します。内部的には、提供されたクロージャが返すメッセージを使用して `send_message` を呼び出します。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // テキストを受け取り、それを `Msg::Text` メッセージバリアントとしてコンポーネントに送信するコールバックを作成します。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上の行は冗長であり、より明確にするために次のように簡略化できます：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // `Msg::Text(\"Hello World!\")` をコンポーネントに送信します。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // ここに HTML を配置\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nバッチメッセージを送信するコールバックを作成します。このメソッドに渡されるクロージャはメッセージを返す必要はありません。代わりに、クロージャは `Vec<Msg>` または `Option<Msg>` を返すことができます。ここで、`Msg` はコンポーネントのメッセージタイプです。\n\n`Vec<Msg>` はバッチメッセージとして扱われ、内部的に `send_message_batch` を使用します。\n\n`Option<Msg>` は値が `Some` の場合に `send_message` を呼び出します。値が `None` の場合は何も実行しません。これは、更新が不要な場合に使用できます。\n\nこれは、これらの型に対してのみ実装された `SendAsMessage` トレイトを使用して実現されています。独自の型に対して `SendAsMessage` を実装することで、`batch_callback` でそれらを使用できるようになります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/agents.mdx",
    "content": "---\ntitle: 'エージェント (Agents)'\ndescription: 'Yew のエージェントシステム'\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nエージェント (Agents) は、タスクを Web Workers にオフロードする方法です。\n\nエージェントが並行して動作できるようにするために、Yew は [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) を使用します。\n\n## ライフサイクル\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## エージェントの種類\n\n### 範囲\n\n- 公開 - 任意の時点で、公開エージェントのインスタンスは最大で1つだけです。ブリッジはWeb Worker内でエージェントを生成するか、既に生成されたエージェントに接続します。ブリッジがこのエージェントに接続されていない場合、エージェントは消滅します。\n\n- 私有 - 新しいブリッジごとにWeb Worker内で新しいエージェントを生成します。これは、ブラウザと通信する共有だが独立した動作をコンポーネントから移動するのに適しています。接続されたブリッジが破棄されると、エージェントは消滅します。\n\n- グローバル \\(WIP\\)\n\n## エージェントとコンポーネント間の通信\n\n### 通信ブリッジ (Bridges)\n\n通信ブリッジ（ブリッジ）は、コンポーネントとエージェント間の通信チャネルです。これにより、コンポーネントはエージェントにメッセージを送信し、エージェントからのメッセージを受信できます。\n\n`use_bridge` フックは、関数コンポーネント内でブリッジを作成する機能も提供します。\n\n### ディスパッチャー (Dispatchers)\n\nディスパッチャー（ディスパッチャー）は、コンポーネントとエージェント間の一方向通信を可能にし、コンポーネントがこの方法でエージェントにメッセージを送信します。\n\n## オーバーヘッド\n\nエージェントはWeb Workers（つまり、私有および公開）を使用します。メッセージの送受信時にシリアル化オーバーヘッドが発生します。エージェントは [bincode](https://github.com/bincode-org/bincode) を使用して他のスレッドと通信するため、コストは関数を呼び出すだけの場合よりもはるかに高くなります。\n\n## さらなる読み物\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) の例は、コンポーネントがエージェントにメッセージを送信し、エージェントからのメッセージを受信する方法を示しています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'classes! マクロを使用して CSS クラスを処理する'\ndescription: '便利なマクロを使用して CSS クラスを処理する'\ncomment: 'ファイルを短くシンプルに保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためであり、正確な API ドキュメントを提供するためではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew はネイティブの CSS-in-Rust ソリューションを提供していませんが、HTML の `class` 属性とプログラム的に対話する方法を提供することでスタイルを支援します。\n\n## `classes!` マクロ\n\n`classes!` マクロと関連する `Classes` 構造体は、HTML クラスの使用を簡素化します：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。\n\n## インラインスタイル\n\n現在、Yew は `style` 属性を使用して指定されたインラインスタイルを処理するための特別な支援ツールを提供していませんが、他の HTML 属性と同様に処理することができます：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'html! マクロを使用してHTMLを処理する'\ndescription: 'これはHTMLですが、完全にそうではありません！'\ncomment: 'ファイルを短く簡潔に保つようにしてください。これは、読者がYewのコンポーネントをより簡単に理解できるようにするためであり、正確なAPIドキュメントを提供するためではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロを使用して、HTML に似た式を記述できます。Yew はバックグラウンドでそれを DOM を表現する Rust コードに変換します。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nフォーマットされた式と同様に、波括弧を使用して周囲のコンテキストの値を HTML に埋め込むことができます：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n`html!` を使用する際の重要なルールの 1 つは、1 つのラッピングノードしか返せないということです。複数の要素のリストをレンダリングするために、`html!` は空のタグ（フラグメント）の使用を許可しています。空のタグは名前のないタグで、それ自体は HTML 要素を生成しません。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// エラー：ルート HTML 要素は1つだけ許可されています\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修正：HTML 空のタグを使用してラップする\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n詳細については、[HTML の詳細](concepts/html/introduction.mdx)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JavaScript と Rust'\ndescription: 'Rust で JavaScript を使用する'\ncomment: 'ファイルを簡潔に保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためのものであり、正確な API ドキュメントを提供するためのものではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew は、再利用可能な UI 部分に必要なすべてのコンテンツを1か所に集める一方で、必要に応じて基盤技術へのアクセスも維持します。\n\n今日現在、WebAssembly は DOM との相互作用を完全にはサポートしていません。これは、Yew でも時々 JavaScript の呼び出しに依存することを意味します。次に、関係するライブラリの概要を示します。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しの橋を架けるライブラリとツールです。\n\n彼らの[ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/)と私たちの[クイックガイド](./wasm-bindgen.mdx)を強くお勧めします。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) は Web API のバインディングを提供し、Rust で処理され安全な方法で JavaScript コードを書くことを可能にします。\n\n例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n繰り返しになりますが、彼らの[ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/)と私たちの[クイックガイド](./web-sys.mdx)を強くお勧めします。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しブリッジを作成するためのライブラリおよびツールです。これは [Rust と WebAssembly ワーキンググループ](https://rustwasm.github.io/) によって Rust で構築されました。\n\nYew は `wasm-bindgen` を使用して、いくつかのクレートを介してブラウザと対話します：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nこのセクションでは、これらのクレートをより抽象的なレベルから探求し、Yew での `wasm-bindgen` API の理解と使用を容易にします。`wasm-bindgen` および関連するクレートに関する詳細なガイドについては、[`wasm-bindgen` ガイド](https://wasm-bindgen.github.io/wasm-bindgen/) を参照してください。\n\n上記のクレートのドキュメントについては、[`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) を参照してください。\n\n:::tip\n`wasm-bindgen` doc.rs 検索を使用して、`wasm-bindgen` を使用してインポートされたブラウザ API および JavaScript タイプを見つけます。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nこのクレートは、上記の他のクレートに多くの構成要素を提供します。このセクションでは、`wasm-bindgen` クレートの主要な領域の 2 つ、つまりマクロと、何度も目にするタイプ/トレイトのいくつかについてのみ説明します。\n\n### `#[wasm_bindgen]` マクロ\n\n`#[wasm_bindgen]` マクロは Rust と JavaScript の間のインターフェースを提供し、両者の間で変換を行うシステムを提供します。このマクロの使用はより高度であり、外部の JavaScript ライブラリを使用する場合を除いて使用しないでください。`js-sys` および `web-sys` クレートは、組み込みの JavaScript タイプおよびブラウザ API に対して `wasm-bindgen` 定義を提供します。\n\n`#[wasm-bindgen]` マクロを使用して、特定のバージョンの [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 関数をインポートする簡単な例を見てみましょう。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// まず、`web_sys` を使用せずに `console.log` を手動でバインドしてみましょう。\n// ここでは、手動で `#[wasm_bindgen]` アノテーションを書きます。プログラムの正確性はこれらのアノテーションの正確性に依存します！\n#[wasm_bindgen]\nextern \"C\" {\n    // ここで `js_namespace` を使用して `console.log(..)` をバインドします。`log(..)` だけではありません。\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` は多態的なので、複数のシグネチャを使用してバインドできます。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 複数の引数も可能です！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// インポートされた関数を使用します！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_この例は、[1.2 `wasm-bindgen` ガイドの console.log を使用する](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) に基づいています。_\n\n### 継承のシミュレーション\n\nJavaScript クラス間の継承は、JavaScript 言語のコア機能であり、DOM（ドキュメントオブジェクトモデル）はそれを中心に設計されています。`wasm-bindgen` を使用して型をインポートする際にも、それらの継承関係を記述する属性を追加できます。\n\nRust では、この継承関係は [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) と [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) トレイトを使用して表現されます。ここで例を挙げると役立つかもしれません。例えば、`A`、`B`、`C` という 3 つの型があり、`C` が `B` を拡張し、`B` が `A` を拡張しているとします。\n\nこれらの型をインポートする際、`#[wasm-bindgen]` マクロは次のように `Deref` と `AsRef` トレイトを実装します：\n\n- `C` は `B` に `Deref` できます\n- `B` は `A` に `Deref` できます\n- `C` は `B` に `AsRef` できます\n- `C` と `B` はどちらも `A` に `AsRef` できます\n\nこれらの実装により、`C` のインスタンスで `A` のメソッドを呼び出したり、`C` を `&B` または `&A` として使用したりできます。\n\n注意すべき点は、`#[wasm-bindgen]` を使用してインポートされたすべての型には同じルート型があり、それを上記の例の `A` と見なすことができるということです。この型は [`JsValue`](#jsvalue) であり、以下にそのセクションがあります。\n\n_[`wasm-bindgen` ガイドの extends セクション](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\nこれは JavaScript が所有するオブジェクトの表現であり、`wasm-bindgen` のルートキャプチャ型です。`wasm-bindgen` からの任意の型は `JsValue` です。これは、JavaScript には強い型システムがないため、変数 `x` を受け取る任意の関数がその型を定義しないため、`x` は有効な JavaScript 値である可能性があるためです。したがって `JsValue` です。`JsValue` を受け取るインポート関数や型を使用している場合、技術的には任意のインポート値が有効です。\n\n`JsValue` は関数で受け取ることができますが、その関数は特定の型のみを受け取る可能性があり、それがパニックを引き起こす可能性があります。したがって、元の `wasm-bindgen` API を使用する場合は、インポートされた JavaScript のドキュメントを確認して、その値が特定の型でない場合に例外（パニック）を引き起こすかどうかを確認してください。\n\n_[`JsValue` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)_\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust には強い型システムがありますが、JavaScript にはありません😞。Rust がこれらの強い型を維持しながらも便利であるために、WebAssembly ワーキンググループは非常に巧妙な機能 `JsCast` を提案しました。これは、ある JavaScript \"型\" から別の \"型\" への変換を支援するものです。これは曖昧に聞こえますが、ある型が別の型であることがわかっている場合、`JsCast` の関数を使用してある型から別の型にジャンプできます。`web-sys`、`wasm_bindgen`、`js-sys` を使用する際にこの機能を理解しておくと便利です。これらのクレートから多くの型が `JsCast` を実装していることに気付くでしょう。\n\n`JsCast` はチェック付きとチェックなしの変換メソッドを提供します。したがって、実行時にオブジェクトがどの型であるかわからない場合は、変換を試みることができ、失敗する可能性のある型として [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) や [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) を返します。\n\n一般的な例は [`web-sys`](./web-sys.mdx) で、イベントのターゲットを取得しようとする場合です。ターゲット要素が何であるかを知っているかもしれませんが、[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API は常に [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を返します。\nその要素型に変換する必要があり、そのメソッドを呼び出すことができます。\n\n```rust\n// このトレイトを最初にインポートする必要があります\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // もしかしたらターゲットは選択要素かもしれませんか？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 別のことをする\n        return;\n    }\n\n    // それが選択要素でないことが確実であれば、入力要素であることが確実です！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) メソッドはチェック付きの変換であり、`Option<&T>` を返します。これは、変換が失敗した場合に元の型を再度使用できることを意味し、`None` を返します。 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) メソッドは `self` を消費し、Rust の `into` メソッドの規約に従い、`Result<T, Self>` 型を返します。変換が失敗した場合、元の `Self` 値は `Err` に返されます。再試行するか、元の型で他の操作を行うことができます。\n\n_[`JsCast` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 型は、Rust のクロージャを JavaScript に渡す方法を提供します。健全性の理由から、JavaScript に渡されるクロージャは `'static` ライフタイムを持つ必要があります。\n\nこの型は「ハンドル」であり、破棄されると、それが参照する JS クロージャを無効にします。`Closure` が破棄された後、JS 内のクロージャの使用はすべて例外を引き起こします。\n\n`Closure` は、[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 型を受け取る `js-sys` または `web-sys` API を使用する際に一般的に使用されます。Yew で `Closure` を使用する例は、[Events](../html/events.mdx) ページの[Using `Closure` セクション](../html/events.mdx#using-closure-verbose) にあります。\n\n_[`Closure` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` クレートは、JavaScript の標準組み込みオブジェクトのバインディング/インポートを提供します。これには、それらのメソッドやプロパティが含まれます。\n\nこれは Web API を含みません。Web API は [`web-sys`](./web-sys.mdx) の役割です！\n\n_[`js-sys` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` クレートは、JavaScript の Promise 型を Rust の [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) として扱うためのブリッジを提供し、Rust の Future を JavaScript の Promise に変換するユーティリティを含みます。Rust（wasm）で非同期または他のブロッキング作業を処理する際に役立ち、JavaScript のイベントや JavaScript I/O プリミティブと対話する能力を提供します。\n\n現在、このクレートには3つの主要なインターフェースがあります：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) を使用して構築された型で、`Future<Output=Result<JsValue, JsValue>>` として使用できます。`Promise` が解決されると、この `Future` は `Ok` に解決され、`Promise` が拒否されると `Err` に解決され、それぞれ `Promise` の解決または拒否の値を含みます。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Rust の `Future<Output=Result<JsValue, JsValue>>` を JavaScript の `Promise` に変換します。Future の結果は、JavaScript 内の解決または拒否された `Promise` に変換されます。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   現在のスレッドで `Future<Output = ()>` を生成します。これは、Rust 内で Future を実行する最良の方法であり、JavaScript に送信するのではなく、Rust 内で実行します。\n\n_[`wasm-bindgen-futures` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` は、非同期 API を使用するライブラリを使用する際に、Yew で `wasm-bindgen-futures` クレートの最も一般的に使用される部分です。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // \"Hello, world!\" を出力します\n    console::log_1(&string.into());\n});\n```\n\nYew はいくつかの API に futures のサポートを追加しており、特に `async` ブロックを受け入れる `callback_future` を作成できることが注目されます。これは内部的に `spawn_local` を使用しています。\n\n_[`spawn_local` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys クレートは Web API のバインディングを提供します。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` クレート](https://crates.io/crates/web-sys) は Web API のバインディングを提供します。これはブラウザの WebIDL から生成されるため、名前が長くなったり、型が曖昧になったりすることがあります。\n\n## `web-sys` の特性 (features)\n\n`web-sys` クレートで全ての特性を有効にすると、Wasm アプリケーションに多くの冗長性が追加される可能性があります。この問題を解決するために、ほとんどの型は特性を有効にすることで制御され、アプリケーションに必要な型だけを含めることができます。Yew は `web-sys` のいくつかの特性を有効にし、その公開 API でいくつかの型を公開しています。通常、`web-sys` を依存関係として追加する必要があります。\n\n## `web-sys` の継承\n\n[継承のシミュレーション](./wasm-bindgen.mdx#simulating-inheritance)のセクションでは、Rust が通常 JavaScript の継承をシミュレートする方法を提供していることがわかります。これは `web-sys` で非常に重要です。ある型にどのようなメソッドがあるかを理解するためには、その継承を理解する必要があります。\n\nこのセクションでは、特定の要素を見て、Rust で [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) を呼び出して、その値が [`JsValue`](./wasm-bindgen.mdx#jsvalue) になるまでの継承をリストします。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement は HTML の <textarea> です。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意: ここで web-sys タイプから js-sys クレート内の組み込み JavaScript タイプに移行しました。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意: ここで js-sys タイプから wasm-bindgen クレートのルート JsValue に移行しました。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // このように deref を使用することで、継承ツリーを手動でたどる必要があります。\n    // しかし、HtmlTextAreaElement タイプで JsValue メソッドを呼び出すことができます。\n    assert!(!text_area.is_string());\n\n    // この空の関数は、HtmlTextAreaElement を &EventTarget として渡すことができることを示すためのものです。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // コンパイラはここでタイプを一致させるために deref チェーンを下にたどります。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 実装により、HtmlTextAreaElement を &EventTarget として扱うことができます。\n    let event_target: &EventTarget = text_area.as_ref();\n}\n```\n\n[`wasm-bindgen` ガイドの `web-sys` 継承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)\n\n## `NodeRef` の `Node`\n\nYew は [`NodeRef`](concepts/function-components/node-refs.mdx) を使用して、[`html!`](concepts/html/introduction.mdx) マクロによって作成された `Node` の参照を保持する方法を提供します。`NodeRef` の `Node` は [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html) を指します。`NodeRef::get` メソッドは `Option<Node>` 値を返しますが、Yew ではほとんどの場合、この値を特定の要素に変換して、その特定のメソッドを使用することを望みます。存在する場合、[`JsCast`](./wasm-bindgen.mdx#JsCast) を使用して `Node` 値を変換できますが、Yew はこの変換を実行するための `NodeRef::cast` メソッドを提供しているため、`JsCast` 特性のために `wasm-bindgen` 依存関係を含める必要はありません。\n\n以下の2つのコードブロックは本質的に同じです。最初のものは `NodeRef::cast` を使用し、2 番目のものは `NodeRef::get` が返す `web_sys::Node` 上で [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) を使用しています。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // HtmlInputElement をここで処理します\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // HtmlInputElement をここで処理します\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Rust にリファクタリングされた JavaScript の例\n\nこのセクションでは、Web API と対話する JavaScript コードの例を Rust の `web-sys` にリファクタリングする方法を示します。\n\n### JavaScript の例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e はマウスイベントオブジェクトです\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 要素内の x 位置。\n    var y = e.clientY - rect.top // 要素内の y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` を使用して書き直した例\n\n`web-sys` のみを使用して、上記の JavaScript の例は次のように実装できます：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 使用したいすべての web-sys 機能を有効にする必要があります！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 現在、イベントが発生したときにクロージャがメモリに残るように、`mousemove` クロージャを保存する必要があります。\n```\n\nこのバージョンはより冗長ですが、その一部は失敗した型が私たちにいくつかの関数呼び出しに保持しなければならない不変条件を思い出させるためです。これらの不変条件が守られないと、Rust ではパニックが発生します。もう一つの冗長な部分は、特定のメソッドを呼び出すために異なる型を特定の型に変換するための `JsCast` の呼び出しです。\n\n### Yew で書き直した例\n\nYew では、主に [`Callback`](concepts/function-components/callbacks.mdx) を作成して [`html!`](concepts/html/introduction.mdx) マクロで使用するため、例はこの方法を使用します。上記の方法を完全にコピーするのではなく、この方法を使用します：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# `get_bounding_client_rect` メソッドを使用するには、`DomRect` 特性を有効にする必要があります。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 追加の依存ライブラリ\n\n`web-sys` は Web API の生のバインディングであるため、Rust で使用する際にはいくつかの困難が伴います。これは、`web-sys` が Rust や強い型システムのために設計されていないためです。そこで、コミュニティのクレートが `web-sys` に対する抽象化を提供し、Rust の慣習により適した API を提供しています。\n\n_[追加の依存ライブラリ一覧](/community/external-libs)_\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/contexts.mdx",
    "content": "---\ntitle: 'コンテキスト (Contexts)'\nsidebar_label: コンテキスト\ndescription: 'コンテキストを使用して深くネストされたデータを渡す'\n---\n\n通常、データは props を介して親コンポーネントから子コンポーネントに渡されます。\nしかし、多くの中間コンポーネントを介してデータを渡す必要がある場合や、アプリケーション内の多くのコンポーネントが同じ情報を必要とする場合、props を介してデータを渡すことは冗長で煩わしいものになります。\nコンテキストはこの問題を解決し、親コンポーネントがデータをその下のツリー内の任意のコンポーネントに渡すことを可能にし、props を介してデータを渡す必要がなくなります。\n\n## Props を使用する際の問題：\"Prop Drilling\"\n\n[props](./function-components/properties.mdx) を介してデータを親コンポーネントから直接子コンポーネントに渡すことは良い方法です。\nしかし、深くネストされたコンポーネントツリーを介してデータを渡す必要がある場合や、複数のコンポーネントが同じデータを共有する必要がある場合、props を渡すことは煩雑になります。\n一般的なデータ共有の解決策は、データを共通の祖先に持ち上げ、子コンポーネントがそれを props として受け取るようにすることです。\nしかし、これにより props が複数のコンポーネントを介して渡される必要がある場合があります。\nこの状況は \"Prop Drilling\" と呼ばれます。\n\n以下の例を考えてみましょう。これは props を介してテーマを渡しています：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// アプリのルート\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n私たちはテーマ設定を `Navbar` に渡して、それが `Title` と `NavButton` に到達するようにしています。\nもし `Title` と `NavButton` のようなテーマにアクセスする必要があるコンポーネントが、prop を介さずに直接テーマにアクセスできるとしたら、もっと良いでしょう。\nコンテキストはこの問題を解決し、親コンポーネントがデータ（この場合はテーマ）をその子コンポーネントに渡すことを可能にします。\n\n## コンテキストの使用\n\n### ステップ 1：コンテキストの提供\n\nコンテキストを消費するには、コンテキストプロバイダーが必要です。`ContextProvider<T>` は、`T` がコンテキスト構造体として使用されるプロバイダーです。\n`T` は `Clone` と `PartialEq` を実装する必要があります。`ContextProvider` は、その子コンポーネントがコンテキストを持つコンポーネントです。\nコンテキストが変更されると、子コンポーネントは再レンダリングされます。データを渡すための構造体が定義されます。`ContextProvider` は次のように使用できます：\n\n```rust\nuse yew::prelude::*;\n/// アプリのテーマ\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// メインコンポーネント\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` は `Rc<UseStateHandle<Theme>>` 型であり、`Theme` が必要です\n        // したがって、デリファレンスします。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // ここにあるすべての子コンポーネントとその子コンポーネントは、このコンテキストにアクセスします。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// ツールバー\n/// このコンポーネントはコンテキストにアクセスできます。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// `Toolbar` 内に配置されたボタン\n/// このコンポーネントは、コンポーネントツリー内の `ThemeContextProvider` の子コンポーネントであるため、\n/// コンテキストにアクセスできます。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### ステップ 2：コンテキストの使用\n\n#### 関数コンポーネント\n\n`use_context` フックは、関数コンポーネント内でコンテキストを使用するために使用されます。\n詳細については、[use_context ドキュメント](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) を参照してください。\n\n#### 構造体コンポーネント\n\n構造体コンポーネント内でコンテキストを使用するには、2つの方法があります：\n\n- [高階コンポーネント](../advanced-topics/struct-components/hoc)：高階関数コンポーネントがコンテキストを使用し、必要なデータを構造体コンポーネントに渡します。\n- 構造体コンポーネント内で直接コンテキストを使用します。詳細については、[構造体コンポーネントのコンシューマーとしての例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs) を参照してください。\n\n## 使用シナリオ\n\n通常、ツリーの異なる部分のリモートコンポーネントでデータを使用する必要がある場合、コンテキストが役立ちます。\n以下はいくつかの例です：\n\n- **テーマ**：アプリケーションのトップにコンテキストを配置し、アプリケーションのテーマを保持し、視覚的な外観を調整するために使用できます（上記の例を参照）。\n- **現在のユーザーアカウント**：多くの場合、コンポーネントは現在ログインしているユーザーを知る必要があります。コンテキストを使用して、現在のユーザーオブジェクトをコンポーネントに提供できます。\n\n### コンテキストを使用する前の考慮事項\n\nコンテキストは非常に使いやすいですが、それが誤用/過度に使用される可能性もあります。\n複数のレベル深いコンポーネントに props を共有するためにコンテキストを使用できるからといって、必ずしもそうすべきではありません。\n\n例えば、コンポーネントを抽出して、そのコンポーネントを別のコンポーネントの子コンポーネントとして渡すことができます。\n例えば、`Layout` コンポーネントが `articles` を prop として受け取り、それを `ArticleList` コンポーネントに渡す場合、\n`Layout` コンポーネントをリファクタリングして、子コンポーネントを props として受け取り、`<Layout> <ArticleList {articles} /> </Layout>` と表示するようにするべきです。\n\n## 子コンポーネントのコンテキスト値を変更する\n\nRust の所有権ルールにより、コンテキストには子コンポーネントが呼び出せる `&mut self` メソッドを持つことができません。\nコンテキストの値を変更するには、リデューサーと組み合わせて使用する必要があります。これは、[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) フックを使用して行うことができます。\n\n[コンテキストの例](https://github.com/yewstack/yew/tree/master/examples/contexts) は、可変コンテキストの使用を示しています。\n\n## さらなる読み物\n\n- [コンテキストの例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'コールバック (Callbacks)'\n---\n\nコールバック関数は、コンポーネントツリー内で情報を上向きに伝達したり、イベント処理中に他のコンポーネント（例えばエージェントやDOM）と通信したりするために使用されます。内部的には、コールバック関数の型は単なる `Fn` であり、安価にクローンできるように `Rc` に包まれています。\n\nコールバック関数を手動で呼び出したい場合は、`emit` 関数を使用できます。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // コールバック関数を呼び出す\n// web_sys::console::log_1(&result.into()); // コメントを解除すると、「Bye Bob」 が出力されます\n```\n\n## コールバック関数をプロパティとして渡す\n\nyew で一般的なパターンは、コールバック関数を作成し、それをプロパティとして子コンポーネントに渡すことです。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 次にプロパティ (Props) を提供します\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // コメントを解除すると、ここにテキストが出力されます\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM イベントとコールバック関数\n\nコールバック関数は、DOM イベントに接続するためにも使用されます。\n\n例えば、ここではユーザーがボタンをクリックしたときに呼び出されるコールバック関数を定義します：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // コメントを解除すると、ここにテキストが出力されます\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子要素 (Children)'\n---\n\n`Children` は特別なプロパティタイプで、HTMLの子要素のようにネストされた `Html` を受け取ることができます。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` キーは重要です！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // この方法で子要素を転送できます\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'コンポーネント間の通信'\n---\n\n## 親コンポーネントから子コンポーネントへのメッセージ送信\n\nデータを [props](./properties) として渡すと、再レンダリングが発生し、これが子コンポーネントにメッセージを渡す方法です。\n\n## 子コンポーネントから親コンポーネントへのメッセージ送信\n\nprops を介してコールバックを渡し、子コンポーネントはイベントでそれを呼び出すことができます。[例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'ジェネリックコンポーネント'\ndescription: '関数コンポーネントの #[component] 属性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 属性は、ジェネリックコンポーネントを作成するためのジェネリック関数にも適用されます。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// その後、このように使用できます\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// または\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'カスタムフック'\n---\n\n## カスタムフックの定義\n\nコンポーネントのステートフルなロジックは、カスタムフックを作成することで再利用可能な関数として抽出できます。\n\n例えば、`window` オブジェクト上のイベントをリッスンするイベントリスナーを作成したいとします。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nこのコードには問題があります。ロジックは他のコンポーネントで再利用できません。異なるイベントをリッスンする別のコンポーネントを作成する場合、コードをコピーするのではなく、ロジックをカスタムフックに移すことができます。\n\nまず、`use_event` という新しい関数を作成します。`use_` プレフィックスは関数がフックであることを示します。この関数はイベントターゲット、イベントタイプ、およびコールバックを受け取ります。すべてのフックはその関数定義に `#[hook]` とマークする必要があります。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nこのシンプルなフックは、組み込みのフックを組み合わせることで作成できます。この例では、`use_effect_with` フックを使用します。これにより、フックのパラメータが変更されたときにイベントリスナーを再作成できます。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nこの方法はほとんどすべてのケースで有効ですが、私たちがすでに使用しているような基本的なフックを作成するためには使用できません。\n\n[docs.rs](https://docs.rs/yew) 上のドキュメントや `hooks` ディレクトリを参照して、事前定義されたフックの実装を確認してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks は、状態を保存し、副作用を実行することができる関数の一種です。\n\nYew はいくつかの事前定義された hooks を提供しています。また、自分で hooks を作成することもできますし、多くの[コミュニティ製の hooks](/community/awesome#hooks) を見つけることもできます。\n\n## Hooks のルール\n\n1. 各 Hook 関数の名前は `use_` で始める必要があります\n2. Hooks は次の場所でのみ使用できます：\n    - 関数/ Hook のトップレベル\n    - 関数/ Hook 内のブロック、ただし分岐していない場合\n    - 関数/ Hook 内トップレベルの `if` 式の条件\n    - 関数/ Hook 内トップレベルの `match` 式のセレクター\n3. 各レンダリング時に、Hooks は同じ順序で呼び出される必要があります。[Suspense](../../suspense.mdx) を使用する場合のみ、早期リターンが許可されます\n\nこれらのルールは、コンパイル時または実行時のエラーによって強制されます。\n\n### 事前定義された Hooks\n\nYew は次の事前定義された Hooks を提供しています：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nこれらの hooks のドキュメントは [Yew API ドキュメント](https://yew-rs-api.web.app/next/yew/functional/)で見つけることができます。\n\n### カスタム Hooks\n\n場合によっては、独自の Hooks を定義して、コンポーネント内の状態を持つ可能性のあるロジックを再利用可能な関数にカプセル化することが望ましいことがあります。\n\n## さらなる読み物\n\n- React ドキュメントには [React hooks](https://reactjs.org/docs/hooks-intro.html) に関するセクションがあります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '関数コンポーネント'\nslug: /concepts/function-components\n---\n\n以前のスローガンをもう一度見てみましょう：\n\n> Yew の核心思想は、再利用可能な UI 部分に必要なすべての内容を 1 つの場所 - Rust ファイルに集中させることです。\n\nこの声明を完成させるために、アプリケーションのロジックとレンダリングの動作を定義する概念を導入します：\"コンポーネント\"。\n\n## コンポーネントとは？\n\nコンポーネントは Yew の構成要素です。\n\nそれらは次のことを行うべきです：\n\n- [Props](./properties.mdx) の形式でパラメータを受け取る\n- 独自の状態を持つことができる\n- ユーザーに見える HTML フラグメント（DOM）を計算する\n\n## Yew コンポーネントの 2 つのフレーバー\n\n現在、関数コンポーネントについて読んでいます - これは Yew を使い始めるときや、シンプルなレンダリングロジックを書くときにコンポーネントを書くための推奨方法です。\n\nもう一つの、より高度ですがアクセスしにくいコンポーネントの書き方があります - [構造コンポーネント](advanced-topics/struct-components/introduction.mdx)。それらは非常に詳細な制御を可能にしますが、ほとんどの場合、そこまで詳細な制御は必要ありません。\n\n## 関数コンポーネントの作成\n\n関数コンポーネントを作成するには、関数に `#[component]` 属性を追加します。慣例として、関数の名前は PascalCase を使用し、`html!` マクロ内の通常の html 要素と対比させます。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// そして他の場所で、`html!` 内でコンポーネントを使用できます\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## コンポーネント内部で何が起こっているのか\n\nレンダリング時に、Yew はこれらのコンポーネントの仮想ツリーを構築します。各（関数）コンポーネントの view 関数を呼び出して、DOM の仮想バージョン（VDOM）を計算します。ライブラリのユーザーとして、これを `Html` 型として扱います。上記の例では、次のようになります：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n更新が必要な場合、Yew は再び view 関数を呼び出し、新しい仮想 DOM を以前のバージョンと調整し、新しい/変更された/必要な部分のみを実際の DOM に伝播します。これが **レンダリング** と呼ばれるものです。\n\n:::note\n\n実際には、`Html` は `VNode` の別名に過ぎません - 仮想ノードです。\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'ノード参照'\ndescription: 'DOM 外部アクセス'\n---\n\n`ref` 属性を使用して、`NodeRef` を HTML 要素にアタッチできます。コールバック内で、`ref` がアタッチされた DOM `Element` を取得できます。これを使用して、`view` ライフサイクルメソッドの外部で DOM を変更したり、`<input>` の値を取得したり、JavaScript API を介して直接 DOM と対話したりできます。\n\nこれは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。\n\n:::caution\nYew がレンダリングした DOM ツリーを手動で変更しないでください。確信が持てない場合は、`NodeRef` を読み取り専用アクセスとして扱ってください。\n:::\n\n## さらに読む\n\n- [use_node_ref フック](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` の例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Properties)'\ndescription: '親子コンポーネントの通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nプロパティ (Properties) は通常 \"Props\" と略されます。\n\n:::\n\nプロパティ (Properties) はコンポーネントのパラメータであり、Yew はこれらのパラメータを監視できます。\n\nコンポーネントのプロパティで型を使用する前に、その型は `Properties` トレイトを実装している必要があります。\n\n## リアクティブ性\n\n再レンダリング時に、Yew は仮想DOMを調整する際にプロパティが変更されたかどうかを確認し、ネストされたコンポーネントを再レンダリングする必要があるかどうかを判断します。これにより、Yew は非常にリアクティブなフレームワークと見なされます。親コンポーネントからの変更は常に下位に伝播し、ビューはプロパティ/状態からのデータと常に同期します。\n\n:::tip\n\nまだ [チュートリアル](../../tutorial) を完了していない場合は、このリアクティブ性を自分でテストしてみてください！\n\n:::\n\n## 派生マクロ\n\nYew は、構造体に `Properties` トレイトを簡単に実装できる派生マクロを提供します。\n\n`Properties` を派生する型は、Yew がデータ比較を行えるように `PartialEq` も実装している必要があります。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 関数コンポーネントでの使用\n\n属性 `#[component]` は、関数の引数で Props を選択的に受け取ることを可能にします。それらを提供するには、`html!` マクロ内の属性を通じて割り当てることができます。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// そしてプロパティを提供します\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 提供するプロパティはありません\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生マクロフィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。\n\n以下の属性を使用すると、親コンポーネントがそれらを設定しなかった場合にデフォルト値を提供することができます。\n\n:::tip\n属性は Rustdoc によって生成されたドキュメントには表示されません。属性のドキュメント文字列には、その属性がオプションであるかどうか、および特定のデフォルト値があるかどうかを記載する必要があります。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n`Default` トレイトを使用して、フィールド型のデフォルト値でプロパティ値を初期化します。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。\n\n例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。プロパティが構築されるときに、式が評価され、明示的な値が与えられていない場合に適用されます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n属性値を初期化するために `function` を呼び出します。`function` は `FnMut() -> T` シグネチャを持つ必要があり、ここで `T` はフィールドの型です。このプロパティに明示的な値が与えられていない場合、その関数が呼び出されます。\nこの関数はプロパティが構築されるときに呼び出されます。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたスマートポインタとして渡されます。これにより、コンポーネントツリー内のプロパティに対して共有ポインタが1つだけ渡されるため、プロパティ全体をクローンする高コストを節約できます。\n\n:::tip\n`AttrValue` はプロパティ値に使用するカスタムタイプであり、これにより String やその他のクローンコストが高いタイプとして定義する必要がなくなります。\n:::\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、プロパティや基本式 (`Foo { ..base }`) を使用することはできません。タイプパスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 名前属性を指定する必要はありません\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自動生成プロパティ (yew-autoprops)\n\n開発プロセスを簡素化するために、`#[autoprops]` マクロ（`yew-autoprops` パッケージから）を使用して `Properties` 構造体を自動生成することもできます。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] マクロは #[component] の前に配置する必要があります。順序が重要です。\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 構造体 \"GreetingsProps\" は自動的に生成されます。\n//\n// `is_loading` は値としてコンポーネントに渡され、`message` と `name` は定義に先行する `&` があるため参照として渡されます。\n```\n\n## 評価順序\n\n属性は指定された順序で評価されます。以下の例を参照してください：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## アンチパターン\n\nほとんどのRust型はプロパティとして渡すことができますが、避けるべきアンチパターンがいくつかあります。これらには以下が含まれますが、これに限定されません：\n\n1. `String` 型を `AttrValue` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `String` のクローンは高コストです。プロパティ値がフックやコールバックと一緒に使用される場合、通常クローンが必要です。`AttrValue` は参照カウントされた文字列 (`Rc<str>`) または `&'static str` であり、非常に安価にクローンできます。<br />\n   **注意**：`AttrValue` は内部的には [implicit-clone](https://crates.io/crates/implicit-clone) からの `IString` です。詳細はそのパッケージを参照してください。\n2. 内部可変性を使用する。 <br />\n   **なぜ悪いのか？** 内部可変性（例えば `RefCell`、`Mutex` など）は _通常_ 避けるべきです。これにより再レンダリングの問題が発生する可能性があり（Yewは状態が変更されたことを認識しません）、手動で再レンダリングを強制する必要があるかもしれません。すべてのものと同様に、適切な使用場所があります。慎重に使用してください。\n3. `Vec<T>` 型を `IArray<T>` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `Vec<T>` も `String` と同様にクローンのコストが高いです。`IArray<T>` は参照カウントされたスライス (`Rc<[T]>`) または `&'static [T]` であり、非常に安価にクローンできます。<br />\n   **注意**：`IArray` は [implicit-clone](https://crates.io/crates/implicit-clone) からインポートできます。詳細はそのパッケージを参照してください。\n4. 新しい発見があるかもしれません。早く知っておきたかったエッジケースに遭遇しましたか？問題を作成するか、このドキュメントに修正のPRを提供してください。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) は実験的なパッケージで、関数の引数に基づいて動的にProps構造体を作成することを可能にします。プロパティ構造体が再利用されない場合、これは有用かもしれません。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '純粋コンポーネント'\n---\n\nすべての関数コンポーネントは、プロパティオブジェクトを受け取り、`Html` オブジェクトを返す[純粋](https://ja.wikipedia.org/wiki/%E7%B4%94%E9%96%A2%E6%95%B0)関数です。純粋関数とは、同じ入力に対して常に同じ出力を返す関数のことです。\n\nこの例は純粋コンポーネントです。与えられたプロパティ `is_loading` に対して、常に同じ `Html` を返し、副作用はありません。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n内部の純粋コンポーネントがフックや他のコンポーネントメカニズムを使用しない場合、それを `Html` を返す通常の関数として記述することができ、Yew がコンポーネントのライフサイクルに関連するオーバーヘッドを回避することができます。[式構文](concepts/html/literals-and-expressions.mdx#expressions) を使用して `html!` 内でそれらをレンダリングします。\n:::\n\n## 非純粋コンポーネント\n\nコンポーネントがグローバル変数を使用しない場合、それが「純粋」でない可能性があるかどうか疑問に思うかもしれません。なぜなら、それは毎回レンダリングされる固定関数として呼び出されるだけだからです。\nこれが次のトピック - [フック](./hooks) の出番です。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/state.mdx",
    "content": "---\ntitle: '状態'\n---\n\n## 状態を保存するための一般的なビュー\n\nこの表は、どの状態保存タイプがあなたのユースケースに最適かを決定するためのガイドとして役立ちます：\n\n| フック             | タイプ                     | いつレンダリングされるか                   | スコープ                     |\n| ------------------ | -------------------------- | ------------------------------------------ | ---------------------------- |\n| [use_state]        | `T`                        | 値が設定されたとき                         | コンポーネントインスタンス内 |\n| [use_state_eq]     | `T: PartialEq`             | 異なる値が設定されたとき                   | コンポーネントインスタンス内 |\n| [use_reducer]      | `T: Reducible`             | リデューサーが呼び出されたとき             | コンポーネントインスタンス内 |\n| [use_reducer_eq]   | `T: Reducible + PartialEq` | リデューサーが呼び出され、結果が異なるとき | コンポーネントインスタンス内 |\n| [use_memo]         | `Deps -> T`                | 依存関係が変わったとき                     | コンポーネントインスタンス内 |\n| [use_callback]     | `Deps -> Callback<E>`      | 依存関係が変わったとき                     | コンポーネントインスタンス内 |\n| [use_mut_ref]      | `T`                        | -                                          | コンポーネントインスタンス内 |\n| グローバル静的定数 | `T`                        | -                                          | グローバル、どこでも使用可能 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/classes.mdx",
    "content": "---\ntitle: 'クラス'\ndescription: 'クラスを処理するための便利なマクロ'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## クラス\n\n`Classes` 構造体は、HTML クラスを処理するために使用できます。\n\n文字列をコレクションにプッシュすると、`Classes` は各クラスが一つの要素を持つことを保証します。単一の文字列が複数のクラスを含む場合でも同様です。\n\n`Classes` は、`Extend`（例：`classes1.extend(classes2)`）や `push()`（例：`classes1.push(classes2)`）を使用してマージすることもできます。`Into<Classes>` を実装している任意の型を既存の `Classes` にプッシュすることができます。\n\n`classes!` は、単一の `Classes` を作成するための便利なマクロです。その入力はカンマで区切られた式のリストを受け入れます。唯一の要件は、各式が `Into<Classes>` を実装していることです。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## クラスを受け入れるコンポーネント\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/components.mdx",
    "content": "---\ntitle: 'コンポーネント'\ndescription: 'コンポーネント階層を使用して複雑なレイアウトを作成する'\n---\n\n## 基本\n\nコンポーネントは `html!` マクロで使用できます：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // プロパティなし\n        <MyComponent />\n\n        // プロパティを使用\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // すべてのプロパティを一度に提供\n        <MyComponentWithProps ..props.clone() />\n\n        // 変数のプロパティを使用し、特定の値を上書き\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## ネスト\n\nコンポーネントの `Properties` に `children` フィールドがある場合、子コンポーネント/要素を受け入れることができます。\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` マクロは、各プロパティを個別に指定するのではなく、基本式を `..props` 構文で渡すことを可能にします。これは Rust の[関数的更新構文](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax)に似ています。\nこの基本式は、個別のプロパティを渡した後に現れる必要があります。\n`children` フィールドを持つ基本 props 式を渡す場合、`html!` マクロ内で渡された子要素は、props 内に既に存在する子要素を上書きします。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子要素は props.children を上書きします\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 参考例\n\n- [関数型 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [関数型ルーティング](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '条件レンダリング'\ndescription: 'HTMLで条件付きノードをレンダリングする！'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If ブロック\n\n条件付きでマークアップをレンダリングするには、それを `if` ブロックでラップします：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/elements.mdx",
    "content": "---\ntitle: '要素'\ndescription: 'HTML および SVG 要素のサポート'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM ノード\n\nYew で DOM ノードを手動で作成または管理する理由はたくさんあります。たとえば、管理されたコンポーネントと競合する可能性のある JS ライブラリとの統合などです。\n\n`web-sys` を使用すると、DOM 要素を作成して `Node` に変換できます。次に、`VRef` を使用して `Html` 値として使用できます：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // メモ化された関数、一度だけ実行されます\n    let node = use_memo(\n        (),\n        |_| {\n            // ドキュメントから div 要素を作成\n            let div: Element = document().create_element(\"div\").unwrap();\n            // コンテンツ、クラスなどを追加\n            div.set_inner_html(\"Hello, World!\");\n            // Element を Node に変換\n            let node: Node = div.into();\n            // その Node を Html 値として返す\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo は Rc ポインタを返すので、参照解除とクローンが必要です\n    (*node).clone()\n}\n\n```\n\n## 動的なタグ名\n\n高階コンポーネントを構築する際、タグ名が静的ではない状況に遭遇することがあります。例えば、`Title` コンポーネントがあり、レベル属性に応じて `h1` から `h6` までの任意の内容をレンダリングする場合です。大きなマッチ式を使用する代わりに、Yew は `@{name}` を使用してタグ名を動的に設定することを許可します。ここで、`name` は文字列を返す任意の式です。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 論理値属性\n\nいくつかのコンテンツ属性（例えば、checked、hidden、required）は論理値属性と呼ばれます。Yew では、論理値属性はブール値に設定する必要があります：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nこれは次の **HTML** と機能的に同等です：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n論理値属性を false に設定することは、その属性を使用しないことと同等です。論理式の値を使用することもできます：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nこれは次の **HTML** と機能的に同等です：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 文字列に似た属性\n\nいくつかの論理値属性に加えて、多くの文字列に似た HTML 属性を扱うことがあります。Yew には、文字列に似た値をコンポーネントに渡すためのいくつかのオプションがあります。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nそれらはすべて有効ですが、特にクローンを作成する必要がある場合や、別のコンポーネントに属性として渡す必要がある場合は、Yew のカスタム `AttrValue` を使用することをお勧めします。\n\n## HTML 要素のオプション属性\n\nほとんどの HTML 属性はオプションの値（Some(x) または None）を使用できます。これにより、属性がオプションとしてマークされている場合にその属性を省略できます。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n属性が `None` に設定されている場合、その属性は DOM に設定されません。\n\n## 関連例\n\n- [インライン HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/events.mdx",
    "content": "---\ntitle: 'イベント'\n---\n\n## 紹介\n\nYew は [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) クレートと統合されており、このクレートのイベントを使用します。以下の[表](#event-types)には、`html!` マクロで受け入れられるすべての `web-sys` イベントが一覧表示されています。\n\n下記の表に記載されていないイベントについても、[`Callback`](../function-components/callbacks.mdx) を追加してリッスンすることができます。詳細は[手動イベントリスナー](#manual-event-listener)を参照してください。\n\n## イベントタイプ\n\n:::tip\nすべてのイベントタイプは `yew::events` に再エクスポートされています。\n`yew::events` のタイプを使用することで、`web-sys` を手動でクレートに依存関係として追加するよりも、バージョン互換性を確保しやすくなります。\nYew が指定するバージョンと競合するバージョンを使用することがなくなります。\n:::\n\nイベントリスナーの名前は、`html` マクロでイベント `Callback` を追加する際に期待される名前です：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nイベント名はリスナー名から \"on\" プレフィックスを削除したもので、したがって `onclick` イベントリスナーは `click` イベントをリッスンします。ページの最後にある[完全なイベントリスト](#available-events)とそのタイプを参照してください。\n\n## イベントキャプチャ {#event-bubbling}\n\nYew がディスパッチするイベントは仮想 DOM 階層に従い、リスナーに向かってバブルアップします。現在、リスナーのバブルフェーズのみがサポートされています。仮想 DOM 階層は通常（ただし常にではありません）実際の DOM 階層と同じです。[ポータル](../../advanced-topics/portals)やその他の高度な技術を扱う際には、この違いが重要です。よく設計されたコンポーネントでは、直感的にイベントは子コンポーネントから親コンポーネントにバブルアップするはずです。これにより、`html!` で記述した階層がイベントハンドラによって観察される階層となります。\n\nイベントのバブルアップを避けたい場合は、アプリケーションを起動する前に以下のコードを呼び出すことができます\n\n```rust\nyew::set_event_bubbling(false);\n```\n\nアプリケーションを起動する*前に*。これによりイベント処理が高速化されますが、期待されるイベントを受信しないために一部のコンポーネントが動作しなくなる可能性があります。慎重に使用してください！\n\n## イベントデリゲート\n\n驚くかもしれませんが、イベントリスナーはレンダリングされた要素に直接登録されるわけではありません。代わりに、イベントは Yew アプリケーションのサブツリーのルートノードから委譲されます。ただし、イベントはそのネイティブ形式で渡され、合成形式は作成されません。これにより、HTML リスナーで予期されるイベントと Yew で発生するイベントとの間に不一致が生じる可能性があります。\n\n- [`Event::current_target`] はリスナーが追加された要素ではなく、Yew サブツリーのルートノードを指します。基になる `HtmlElement` にアクセスしたい場合は、[`NodeRef`](../function-components/node-refs.mdx) を使用してください。\n- [`Event::event_phase`] は常に [`Event::CAPTURING_PHASE`] です。内部的には、イベントはバブリングフェーズにあるかのように振る舞い、イベント伝播が再生され、イベントは[上位にバブルアップ](#event-bubbling)します。つまり、仮想 DOM 内の上位のイベントリスナーが下位のイベントリスナーの後にトリガーされます。現在、Yew はキャプチャリスナーをサポートしていません。\n\nこれも意味するところは、Yew によって登録されたイベントは通常、他のイベントリスナーよりも先にトリガーされるということです。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 型付きイベントターゲット\n\n:::caution\nこのセクションでは、**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** は常にイベントが発生した要素を指します。\n\nこれは**必ずしも** `Callback` が配置された要素を指すわけではありません。\n:::\n\nイベント `Callback` の中で、イベントのターゲットを取得したい場合があります。例えば、`change` イベントは何かが変更されたことを通知するだけで、具体的な情報を提供しません。\n\nYew では、正しい型でターゲット要素を取得する方法がいくつかあり、ここで順を追って説明します。イベント上の [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を呼び出すと、オプションの [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 型が返されますが、入力要素の値を知りたい場合にはあまり役に立たないかもしれません。\n\n以下のすべての方法で、同じ問題を解決します。これにより、方法の違いが明確になり、問題に対処することができます。\n\n**問題：**\n\n`<input>` 要素に `onchange` `Callback` があり、呼び出されるたびにコンポーネントに[更新](components#update) `Msg` を送信したいとします。\n\n`Msg` 列挙型は次のようになります：\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### `JsCast` の使用\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) クレートには便利なトレイトがあります：[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)。これにより、型が `JsCast` を実装している限り、型間の直接キャストが可能になります。慎重にキャストすることもできますが、これはランタイムチェックと `Option` や `Result` のロジックを処理することを伴います。また、強制的にキャストすることもできます。\n\nコードを見てみましょう：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# JsCast を呼び出すために wasm-bindgen が必要です\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // イベントが作成されたとき、ターゲットは未定義であり、ディスパッチされるときにのみターゲットが追加されます。\n            let target: Option<EventTarget> = e.target();\n            // イベントはバブルアップする可能性があるため、\n            // このリスナーは HtmlInputElement 型ではない子要素のイベントをキャッチする可能性があります。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // target が HtmlInputElement であることを理解している必要があります。\n        // そうでない場合、value を呼び出すと未定義の動作（UB）になります。\n        // ここでは、これが入力要素であることを確信しているため、チェックせずに適切な型に変換できます。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` が提供するメソッドは [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) と [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into) です。これらのメソッドを使用すると、`EventTarget` から [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html) への変換が可能になります。`dyn_into` メソッドは慎重で、実行時に型が実際に `HtmlInputElement` であるかどうかをチェックし、そうでない場合は `Err(JsValue)` を返します。[`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) は汎用型で、元のオブジェクトを返し、別の型への変換を再試行することができます。\n\nここで、危険なバージョンを使用するタイミングについて考えるかもしれません。上記のケースでは、子要素のない要素に `Callback` を設定しているため、ターゲットは同じ要素である必要があるため、安全です<sup>1</sup>。\n\n_<sup>1</sup> JS の領域に関わる限り、安全です。_\n\n### `TargetCast` の使用\n\n**[JsCast の使用](#using-jscast) を先に読むことを強くお勧めします！**\n\n:::note\n`TargetCast` は新しいユーザーが `JsCast` の動作を理解するために設計されていますが、範囲はイベントとそのターゲットに限定されています。\n\n`TargetCast` または `JsCast` を選択するのは純粋に個人の好みの問題であり、実際には `TargetCast` の実装と `JsCast` の機能は非常に似ています。\n:::\n\n`TargetCast` トレイトは `JsCast` の上に構築されており、イベントから型付きのイベントターゲットを取得するために特化されています。\n\n`TargetCast` は Yew の一部であるため、依存関係を追加せずにイベント上でトレイトメソッドを使用できますが、その動作は `JsCast` と非常に似ています。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // target が HtmlInputElement であることを理解している必要があります。\n        // そうでない場合、value を呼び出すと未定義の動作（UB）になります。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nもし `JsCast` についてすでに知っているか、このトレイトに精通している場合、`TargetCast::target_dyn_into` が `JsCast::dyn_into` に似ていることに気付くでしょうが、イベントのターゲットに特化しています。`TargetCast::target_unchecked_into` は `JsCast::unchecked_into` に似ているため、上記の `JsCast` に関するすべての警告が `TargetCast` にも適用されます。\n\n### `NodeRef` の使用\n\n[`NodeRef`](../function-components/node-refs.mdx) は、与えられたイベントを `Callback` に渡す代わりに使用できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`NodeRef` を使用すると、イベントを無視して `NodeRef::cast` メソッドを使用して `Option<HtmlInputElement>` を取得できます。これはオプションであり、`NodeRef` を設定する前に `cast` を呼び出すか、型が一致しない場合に `None` を返します。\n\n`NodeRef` を使用することで、常に `input_node_ref` にアクセスできるため、状態に `String` を送信する必要がないことがわかるかもしれません。したがって、次のようにすることができます：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // value に対して何かを行う\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nどの方法を選択するかは、コンポーネントと個人の好みによります。*推奨される*方法はありません。\n\n## 手動イベントリスナー\n\nYew の `html` マクロがサポートしていないイベントをリッスンしたい場合があります。サポートされているイベントのリストは[こちら](#event-types)を参照してください。\n\n手動で要素にイベントリスナーを追加するには、[`NodeRef`](../function-components/node-refs.mdx) を使用して、`use_effect_with` 内で [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) と [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API を使用してリスナーを追加します。\n\n以下の例では、架空の `custard` イベントにリスナーを追加する方法を示します。Yew がサポートしていないすべてのイベントやカスタムイベントは、[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) として表現できます。カスタム/サポートされていないイベントの特定のメソッドやフィールドにアクセスする必要がある場合は、[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) のメソッドを使用して必要な型に変換できます。\n\n### `Closure` を使用する（冗長バージョン）\n\n直接 `web-sys` と `wasm-bindgen` のインターフェースを使用するのは少し面倒かもしれません……なので、心の準備をしてください（[`gloo` のおかげで、より簡潔な方法があります](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 通常作成する Callback を作成\n                    let oncustard = Callback::from(move |_: Event| {\n                        // カスタードに対して何かを行う..\n                    });\n\n                    // Box<dyn Fn> から Closure を作成 - これは 'static である必要があります\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n`Closure` の詳細については、[wasm-bindgen ガイド](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html) を参照してください。\n\n### `gloo` を使用する（簡潔なバージョン）\n\nより便利な方法は、`gloo`、具体的には [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html) を使用することです。\nこれは `web-sys`、`wasm-bindgen` の高レベル抽象実装です。\n\n`gloo_events` は、イベントリスナーを作成および保存するために使用できる `EventListener` 型を提供します。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 通常作成する Callback を作成\n                    let oncustard = Callback::from(move |_: Event| {\n                        // カスタードに対して何かを行う..\n                    });\n\n                    // Box<dyn Fn> から Closure を作成 - これは 'static である必要があります\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n`EventListener` の詳細については、[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html) を参照してください。\n\n## 利用可能なイベントの完全なリスト {#available-events}\n\n| リスナー名                  | `web_sys` イベントの種類                                                              |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空のタグ (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロは常にルートノードを必要とします。この制限を回避するために、「空のタグ」（または fragments）を使用できます。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// エラー: ルート HTML 要素は1つだけ許可されます\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'HTML および SVG を生成するためのプロシージャルマクロ'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロを使用すると、宣言的に HTML および SVG コードを記述できます。これは、JavaScript で HTML に似たコードを記述できる拡張機能である JSX に似ています。\n\n**重要な注意点**\n\n1. `html! {}` マクロは 1 つのルート HTML ノードしか受け入れません（これを回避するには、[fragments](./fragments.mdx) または [iterators](./../html/lists.mdx) を使用できます）\n2. 空の `html! {}` 呼び出しは有効で、何もレンダリングしません\n3. リテラルは常に引用符で囲み、中括弧で囲む必要があります：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` マクロはすべてのタグ名を小文字に変換します。大文字の文字（特定の SVG 要素に必要な文字）を使用するには、[動的タグ名](concepts/html/elements.mdx#dynamic-tag-names) を使用してください：`html! { <@{\"myTag\"}></@> }`\n\n:::note\n`html!` マクロはコンパイラのデフォルトの再帰制限に達する可能性があります。コンパイル エラーが発生した場合は、クレートのルートに `#![recursion_limit=\"1024\"]` のような属性を追加して問題を解決してください。\n:::\n\n## タグ (Tags) 構造\n\nタグ (Tags) は HTML タグに基づいています。コンポーネント、要素、およびリストはすべてこのタグ構文に基づいています。\n\nタグは自己閉鎖 `<... />` であるか、開始タグごとに対応する終了タグが必要です。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 閉じタグがありません\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 閉じタグがありません\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n便利のために、通常は閉じタグが必要な要素も**自己閉じ**が許可されています。例えば、`html! { <div class=\"placeholder\" /> }` と記述することができます。\n:::\n\n複雑なネストされた HTML および SVG レイアウトを作成するのは依然として簡単です：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nもし、Rust コンパイラの開発者バージョンを使用して Yew をコンパイルする場合、マクロは一般的な落とし穴について警告します。もちろん、安定版コンパイラを使用してリリースビルドを行う必要があるかもしれません（例えば、組織のポリシーでそうする必要がある場合など）。しかし、安定版ツールチェーンを使用している場合でも、`cargo +nightly check` を実行すると、HTML コードを改善する方法がいくつか示されるかもしれません。\n\n現在、これらのリントは主にアクセシビリティに関連しています。リントに関するアイデアがあれば、[この問題](https://github.com/yewstack/yew/issues/1334)に自由にコメントしてください。\n\n## 属性とプロパティの指定\n\n属性は通常の HTML と同じ方法で要素に設定されます：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n属性は要素名の前に `~` を使用して指定されます：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n値がリテラルの場合、値を囲む中括弧は省略できます。\n\n:::\n\n:::note リテラルとは\n\nリテラルは、Rust のすべての有効な[リテラル式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)です。注意してください、[負の数は**リテラルではありません**](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)、したがって中括弧で囲む必要があります `{-6}`。\n\n:::\n\n:::note コンポーネント属性\nコンポーネント属性は Rust オブジェクトとして渡され、ここで説明されている要素のパラメータ (Attributes) / 属性 (Properties) とは異なります。\n[コンポーネント属性](../function-components/properties.mdx)で詳細を確認してください。\n:::\n\n### 特殊属性\n\nいくつかの特殊な属性があり、これらは直接 DOM に影響を与えるのではなく、Yew 仮想 DOM の指示として機能します。現在、2 つの特殊な属性があります：`ref` と `key`。\n\n`ref` は、基礎となる DOM ノードに直接アクセスして操作することを可能にします。詳細については、[Refs](../function-components/node-refs.mdx)を参照してください。\n\n一方、`key` は要素に一意の識別子を提供し、Yew が最適化のために使用できます。\n\n:::info\n[詳細はこちら](./html/lists)\n:::\n\n## 条件付きレンダリング\n\nRust の条件構造を使用して、条件付きでマークアップをレンダリングできます。現在、`if` と `if let` のみがサポートされています。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n条件付きレンダリングの詳細については、[条件付きレンダリング](./conditional-rendering.mdx)のセクションを参照してください。\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/lists.mdx",
    "content": "---\ntitle: 'リスト'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## イテレータ\n\nイテレータから HTML を構築する方法は 3 つあります：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` ループ\">\n主なアプローチは for ループを使用することです。これは Rust に既に存在する for ループと同じですが、2 つの重要な違いがあります：\n1. 通常の for ループは何も返せませんが、`html!` 内の for ループはノードのリストに変換されます。\n2. `break`、`continue` などの発散式は `html!` 内の for ループの本体では許可されていません。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` ブロック\">\nもう一つの方法は `for` キーワードを使用することです。これはネイティブの Rust 構文ではなく、HTML マクロによってイテレータを表示するために必要なコードを出力します。\nこの方法は、イテレータが既に計算されていて、マクロに渡すだけでよい場合に最初の方法より適しています。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` メソッド\">\n\n最後の方法は、イテレータの最終変換で `collect::<Html>()` を呼び出すことで、Yew が表示できるリストを返します。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## キー付きリスト\n\nキー付きリストは、すべての子要素にキーがある最適化されたリストです。\n`key` は Yew が提供する特別な属性で、HTML 要素やコンポーネントに一意の識別子を与え、Yew 内部での最適化に使用されます。\n\n:::caution\nキーは各リスト内で一意である必要があり、HTML の `id` のようにグローバルに一意である必要はありません。リストの順序に依存してはいけません。\n:::\n\nリストにキーを追加することを常にお勧めします。\n\n一意の `String`、`str`、または整数を特別な `key` 属性に渡すことでキーを追加できます。\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### パフォーマンスの最適化\n\nキー付きリストのパフォーマンス向上をテストするための[例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)があります。以下は簡単なテスト手順です：\n\n1. [オンラインデモ](https://examples.yew.rs/keyed_list)にアクセスします。\n2. 500個の要素を追加します。\n3. キーを無効にします。\n4. リストを反転します。\n5. \"最後のレンダリングにかかった時間 Xms\" を確認します（この記事の執筆時点では約60ms）。\n6. キーを有効にします。\n7. 再度リストを反転します。\n8. \"最後のレンダリングにかかった時間 Xms\" を確認します（この記事の執筆時点では約30ms）。\n\nこの記事の執筆時点では、500個のコンポーネントに対して速度が2倍に向上しました。\n\n### 原理の説明\n\n通常、リストを反復処理する際には、各リスト項目にキーを追加するだけで済みます。データの順序が変わる可能性があるためです。\nリストを再レンダリングする際に、キーは調整プロセスを高速化するために使用されます。\n\nキーがない場合、例えば `[\"bob\", \"sam\", \"rob\"]` を反復処理すると、最終的に以下のようなHTMLが生成されます：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n次のレンダリングでリストが `[\"bob\", \"rob\"]` に変更された場合、Yew は id=\"rob\" の要素を削除し、id=\"sam\" を id=\"rob\" に更新できます。\n\n各要素にキーを追加すると、初期の HTML は変わりませんが、変更後のリスト `[\"bob\", \"rob\"]` をレンダリングすると、Yew は2番目の HTML 要素のみを削除し、他の要素はそのまま残ります。キーを使用して要素を関連付けることができるためです。\n\nコンポーネントから別のコンポーネントに切り替える際に、両方に最高レンダリング要素として div がある場合にバグ/\"機能\" に遭遇した場合。\nYew はこれらの状況で最適化として既にレンダリングされた HTML div を再利用します。\nその div を再利用せずに再作成する必要がある場合は、異なるキーを追加することで再利用されなくなります。\n\n## さらなる読み物\n\n- [TodoMVC の例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [キー付きリストの例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [ルーティングの例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'リテラルと式'\n---\n\n## リテラル\n\n式が `Display` を実装する型に解決される場合、それらは文字列に変換され、[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) ノードとしてDOMに挿入されます。\n\n:::note\n文字列リテラルは `Text` ノードを作成し、ブラウザはそれを文字列として扱います。そのため、式に `<script>` タグが含まれていても、式を `<script>` ブロックでラップしない限り、XSS などのセキュリティ問題に遭遇することはありません。\n:::\n\nすべての表示テキストは式と見なされるため、`{}` ブロックで囲む必要があります。これは、Yew と通常の HTML 構文の最大の違いです。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 式\n\n`{}` ブロックを使用して、HTML 内に式を挿入できます。それらが `Html` に解決される限り。\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常、これらの式を関数やクロージャに抽出して、可読性を最適化することが意味があります：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/router.mdx",
    "content": "---\ntitle: 'ルーター (Router)'\ndescription: 'Yew の公式ルーターライブラリ'\n---\n\nシングルページアプリケーション (SPA) のルーターは、URL に基づいて異なるページを表示する処理を行います。リンクをクリックしたときに異なるリモートリソースを要求するデフォルトの動作とは異なり、ルーターはアプリケーション内の有効なルートを指すようにローカルで URL を設定します。その後、ルーターはこの変更を検出し、レンダリングする内容を決定します。\n\nYew は `yew-router` クレートでルーターサポートを提供します。使用を開始するには、依存関係を `Cargo.toml` ファイルに追加してください。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n必要なツールはすべて `yew_router::prelude` モジュールで提供されています。\n\n## 使用方法\n\nまず、`Route` を定義する必要があります。\n\nルートは `Routable` を派生する `enum` で定義されます。この列挙型は `Clone + PartialEq` を実装する必要があります。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` と `<Switch />` コンポーネントはペアで使用され、後者はブラウザの現在の URL に一致するパスのバリアントを見つけ、それを `render` コールバックに渡します。その後、コールバックがレンダリングする内容を決定します。パスが一致しない場合、ルーターは `not_found` 属性を持つパスにナビゲートします。指定されたルートがない場合、何もレンダリングされず、一致するルートがないことを示すメッセージがコンソールに記録されます。\n\nyew-router のほとんどのコンポーネント、特に `<Link />` と `<Switch />` は、ある Router コンポーネント（例： `<BrowserRouter />`）の（深い）子要素である必要があります。通常、アプリケーションには 1 つの Router しか必要なく、通常は最上位の `<App />` コンポーネントによって直ちにレンダリングされます。Router はコンテキストを登録し、これは Links と Switches の機能に必要です。以下に例を示します。\n\n:::caution\nブラウザ環境で `yew-router` を使用する場合、`<BrowserRouter />` を強く推奨します。他のルータータイプについては [API リファレンス](https://docs.rs/yew-router/) を参照してください。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### パスセグメント\n\nルーターは、動的および名前付きワイルドカードセグメントを使用してルートから情報を抽出することもできます。次に、`<Switch />` 内で投稿の ID にアクセスし、それを適切なコンポーネントにプロパティとして渡すことができます。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n`Post {id: String}` の代わりに通常の `Post` バリアントを使用することもできます。例えば、`Post` が別のルーターと一緒にレンダリングされる場合、そのフィールドは冗長になる可能性があります。詳細については、以下の[ネストされたルーター](#nested-router)セクションを参照してください。\n:::\n\nフィールドは `Route` 列挙型の一部として `Clone + PartialEq` を実装する必要があることに注意してください。また、シリアル化と逆シリアル化のために `std::fmt::Display` と `std::str::FromStr` を実装する必要があります。整数、浮動小数点数、および文字列などのプリミティブ型はこれらの要件を既に満たしています。\n\nパスの形式が一致しても、逆シリアル化が失敗した場合（`FromStr` に基づく）、ルーターはルートが一致しないと見なし、見つからないルートをレンダリングしようとします（または、見つからないルートが指定されていない場合は空白ページをレンダリングします）。\n\n以下の例を参照してください：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch 関数は News と id をレンダリングします。ここでは省略されています。\n```\n\nセグメントが 255 を超えると、`u8::from_str()` は失敗し、`ParseIntError` を返します。この場合、ルーターはルートが一致しないと見なします。\n\n![ルーターの逆シリアル化失敗の動作](/img/router-deserialization-failure-behavior.gif)\n\nルーティング構文やパラメータのバインディング方法の詳細については、[route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params) を参照してください。\n\n### 位置 (Location)\n\nルーターはコンテキストを介して一般的な `Location` 構造体を提供し、ルート情報にアクセスするために使用できます。これらはフックまたは `ctx.link()` 上の便利な関数を介して取得できます。\n\n### ナビゲーション\n\n`yew_router` はナビゲーションを処理するためのいくつかのツールを提供します。\n\n#### リンク\n\n`<Link />` は `<a>` 要素としてレンダリングされ、`onclick` イベントハンドラは [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) を呼び出し、ターゲットページを履歴にプッシュして必要なページをレンダリングします。これはシングルページアプリケーションに期待される動作です。通常のアンカー要素のデフォルトの `onclick` はページをリロードします。\n\n`<Link />` コンポーネントはその子要素を `<a>` 要素に渡します。これはアプリ内ルーティングのための `<a/>` の代替として考えることができます。違いは、`href` の代わりに `to` 属性を提供する必要があることです。使用例は以下の通りです：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n構造体変数も正常に動作します：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### ナビゲーションインターフェース\n\nナビゲーター API は、関数コンポーネントと構造体コンポーネントの両方で提供されます。これにより、コールバックがルートを変更できるようになります。どちらの場合でも、`Navigator` インスタンスを取得してルートを操作できます。\n\n##### 関数コンポーネント\n\n関数コンポーネントの場合、基礎となるナビゲータープロバイダーが変更されると、`use_navigator` フックはコンポーネントを再レンダリングします。\n以下は、クリック時に `Home` ルートにナビゲートするボタンを実装する例です。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\nここでの例では `Callback::from` を使用しています。ターゲットルートがコンポーネントのルートと同じになる可能性がある場合、または安全のために、通常のコールバックを使用してください。例えば、各ページにロゴボタンがあり、そのボタンをクリックするとホームに戻るとします。ホームページでそのボタンを2回クリックすると、同じHomeルートがプッシュされ、`use_navigator` フックが再レンダリングをトリガーしないため、コードがクラッシュします。\n:::\n\n現在の位置をスタックに新しい位置としてプッシュするのではなく置き換えたい場合は、`navigator.push()` の代わりに `navigator.replace()` を使用してください。\n\n`navigator` はコールバックに移動する必要があるため、他のコールバックで再利用できないことに気付くかもしれません。幸いなことに、`navigator` は `Clone` を実装しているため、異なるルートに対して複数のボタンを設定する方法は次のとおりです：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 構造体コンポーネント\n\n構造体コンポーネントの場合、`ctx.link().navigator()` API を使用して `Navigator` インスタンスを取得できます。残りの部分は関数コンポーネントの場合と同じです。以下は、単一のボタンをレンダリングするビュー関数の例です。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### リダイレクト\n\n`yew-router` は prelude に `<Redirect />` コンポーネントも提供しています。これはナビゲーター API と同様の効果を実現するために使用できます。このコンポーネントは、ターゲットルートとして `to` 属性を受け取ります。`<Redirect/>` がレンダリングされると、ユーザーは指定されたルートにリダイレクトされます。以下はその例です：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // `use_user` フックを使用してユーザーを取得\n    let user = match use_user() {\n        Some(user) => user,\n        // ユーザーが `None` の場合、ログインページにリダイレクト\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 実際のページ内容\n}\n```\n\n:::tip `Redirect` と `Navigator` の選択方法\nNavigator API はコールバック内でルートを操作する唯一の方法です。\n一方、`<Redirect />` はコンポーネント内の戻り値として使用できます。また、[ネストされたルーター](#nested-router)の switch 関数など、他の非コンポーネントコンテキストでも `<Redirect />` を使用することができます。\n:::\n\n### 変更のリスニング\n\n#### 関数コンポーネント\n\n`use_location` と `use_route` フックを使用できます。提供された値が変更されると、コンポーネントが再レンダリングされます。\n\n#### 構造体コンポーネント\n\nルートの変更に応答するために、`ctx.link()` の `add_location_listener()` メソッドにコールバッククロージャを渡すことができます。\n\n:::note\n位置リスナーが削除されると、それは登録解除されます。ハンドルをコンポーネントの状態に保存することを確認してください。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // イベントを処理する\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` と `ctx.link().route::<R>()` も、一度だけ位置とルートを取得するために使用できます。\n\n### クエリパラメータ\n\n#### ナビゲーション時にクエリパラメータを指定する\n\n新しいルートにナビゲートする際にクエリパラメータを指定するには、`navigator.push_with_query` または `navigator.replace_with_query` 関数を使用します。これは `serde` を使用してパラメータを URL のクエリ文字列にシリアル化するため、`Serialize` を実装している任意の型を渡すことができます。最も簡単な形式は文字列ペアを含む `HashMap` です。\n\n#### 現在のルートのクエリパラメータを取得する\n\nクエリパラメータを取得するには、`location.query` を使用します。これは `serde` を使用して URL のクエリ文字列からパラメータを逆シリアル化します。\n\n## ネストされたルーター\n\nアプリケーションが大きくなると、ネストされたルーターが役立つ場合があります。次のルーター構造を考えてみましょう：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nネストされた `SettingsRouter` は、すべての `/settings` で始まる URL を処理します。また、一致しない URL をメインの `NotFound` ルートにリダイレクトします。したがって、`/settings/gibberish` は `/404` にリダイレクトされます。\n\n:::caution\n\nこのインターフェースはまだ開発中であり、このように記述する方法は最終決定されていません。\n\n:::\n\n以下のコードで実装できます：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### ベースパス (Basename)\n\n`yew-router` を使用してベースパス (Basename) を定義できます。\nベースパスはすべてのルートの共通プレフィックスです。ナビゲーター API と `<Switch />` コンポーネントはどちらもベースパスの設定をサポートしています。プッシュされるすべてのルートにはベースパスのプレフィックスが追加され、すべてのスイッチはパスを `Routable` に解析する前にベースパスを削除します。\n\nRouter コンポーネントにベースパス属性が提供されていない場合、HTML ファイルの `<base />` 要素の href 属性を使用し、HTML ファイルに `<base />` 要素がない場合は `/` にフォールバックします。\n\n## 関連例\n\n- [ルーター](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## インターフェースリファレンス\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/suspense.mdx",
    "content": "---\ntitle: 'サスペンス (Suspense)'\ndescription: 'データ取得のためのサスペンス'\n---\n\nサスペンス (Suspense) は、タスクが完了するまでコンポーネントのレンダリングを一時停止し、その間にフォールバック（プレースホルダー）UI を表示する方法です。\n\nこれは、サーバーからデータを取得したり、プロキシがタスクを完了するのを待ったり、他のバックグラウンド非同期タスクを実行したりするために使用できます。\n\nサスペンスが表示される前に、データ取得は通常、コンポーネントのレンダリング後（レンダリング時取得）またはレンダリング前（取得後レンダリング）に発生します。\n\n### レンダリングしながらダウンロード\n\nサスペンス (Suspense) は、新しい方法を提供し、コンポーネントがレンダリング中にデータリクエストを発行できるようにします。コンポーネントがデータリクエストを発行すると、レンダリングプロセスが一時停止され、リクエストが完了するまでフォールバック UI が表示されます。\n\nサスペンスを使用するには、フック (Hook) を使用することをお勧めします。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n上記の例では、`use_user` フックはユーザー情報の読み込み中にコンポーネントのレンダリングを一時停止し、`user` が読み込まれる前に `Loading...` プレースホルダーを表示します。\n\nコンポーネントのレンダリングを一時停止するフックを定義するには、`SuspensionResult<T>` を返す必要があります。コンポーネントが一時停止する必要がある場合、フックは `Err(Suspension)` を返すべきであり、ユーザーはそれを `?` でアンパックする必要があります。これにより、それが `Html` に変換されます。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // ユーザーが読み込まれたら、それを Ok(user) として返します。\n        Some(user) => Ok(user),\n        None => {\n            // ユーザーがまだ読み込まれていない場合、`Suspension` を作成し、\n            // データの読み込みが完了したときに `SuspensionHandle::resume` を呼び出します。\n            // これにより、コンポーネントは自動的に再レンダリングされます。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### サスペンスフック (Hook) の実装に関する注意事項\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) は 2 つの値を返します：サスペンスコンテキスト自体とサスペンスハンドル。後者はサスペンスされたコンポーネントを再レンダリングするタイミングを管理し、2 つの方法で操作できます：\n\n1. その [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) メソッドを呼び出す。\n2. ハンドルを破棄する。\n\n:::danger\n\nサスペンスハンドルは、新しいデータを受け取ってコンポーネントを更新するまで保存する必要があります。そうしないと、サスペンスされたコンポーネントが無限再レンダリングループに入り、パフォーマンスに影響を与えます。\n上記の例では、サスペンスハンドルはクロージャに移動し、`on_load_user_complete` に渡されることで保存されます。\n仮想ユーザーが読み込まれると、クロージャが呼び出され、`handle.resume()` が呼び出され、サスペンスコンテキストに関連するコンポーネントが再レンダリングされます。\n\n:::\n\n# 完全な例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 省略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 省略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // ユーザーが読み込まれたら、それを Ok(user) として返します。\n        Some(user) => Ok(user),\n        None => {\n            // ユーザーがまだ読み込まれていない場合、`Suspension` を作成し、\n            // データの読み込みが完了したときに `SuspensionHandle::resume` を呼び出します。\n            // これにより、コンポーネントは自動的に再レンダリングされます。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 構造体コンポーネントでプレースホルダーを使用する\n\n構造体コンポーネントを直接サスペンドすることはできません。しかし、関数コンポーネントを[高階コンポーネント](../advanced-topics/struct-components/hoc)として使用し、プレースホルダーに基づいたデータ取得を実現することができます。\n\nYew リポジトリの[プレースホルダーの例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)は、このコンポーネントの使用方法を示しています。\n\n## 関連例\n\n- [プレースホルダー](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'サンプルアプリケーションの構築'\n---\n\n環境が整ったら、基本的な Yew アプリケーションに必要なテンプレートを使用するか、小さなプロジェクトを手動で設定することができます。\n\n## テンプレートを使用して迅速に開始\n\n[`cargo-generate`](https://github.com/cargo-generate/cargo-generate) のインストール手順に従ってツールをインストールし、次のコマンドを実行します：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手動でアプリケーションを設定する\n\n### プロジェクトの作成\n\nまず、新しい cargo プロジェクトを作成してください。\n\n```bash\ncargo new yew-app\n```\n\n新しく作成したディレクトリを開きます。\n\n```bash\ncd yew-app\n```\n\n### Hello World サンプルを実行する\n\nRust 環境が正しく設定されているかを確認するために、`cargo run` を使用して初期プロジェクトを実行します。\"Hello World!\" メッセージが表示されるはずです。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### プロジェクトを Yew Web アプリケーションに設定する\n\nこのシンプルなコマンドラインアプリケーションを基本的な Yew Web アプリケーションに変換するために、いくつかの変更が必要です。\n\n#### Cargo.toml の更新\n\n依存関係リストに `yew` を追加します。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\nアプリケーションを構築するだけの場合は、`csr` 特性のみが必要です。これにより、`Renderer` とクライアントサイドレンダリングに関連するすべてのコードが有効になります。\n\nライブラリを作成している場合は、この特性を有効にしないでください。クライアントサイドレンダリングロジックがサーバーサイドレンダリングパッケージに含まれることになります。\n\nテストやサンプルのために Renderer が必要な場合は、`dev-dependencies` で有効にするべきです。\n\n:::\n\n#### main.rs の更新\n\nテンプレートを生成し、クリック時に値を更新するボタンをレンダリングする `App` という名前のルートコンポーネントを設定する必要があります。以下のコードで `src/main.rs` の内容を置き換えます。\n\n:::note\n`main` 関数内の `yew::Renderer::<App>::new().render()` 呼び出しは、アプリケーションを起動し、ページの `<body>` タグにマウントします。動的なプロパティを使用してアプリケーションを起動したい場合は、`yew::Renderer::<App>::with_props(..).render()` を使用できます。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### index.html の作成\n\n最後に、アプリケーションのルートディレクトリに `index.html` ファイルを追加します。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## アプリケーションの表示\n\n以下のコマンドを実行して、ローカルでアプリケーションをビルドおよび提供します。\n\n```bash\ntrunk serve\n```\n\n:::info\n`--open` オプションを追加して、デフォルトのブラウザを開くことができます：`trunk serve --open`。\n:::\n\nTrunk は、ソースコードファイルを変更するたびにアプリケーションをリアルタイムで再構築します。\nデフォルトでは、サーバーはアドレス '127.0.0.1' のポート '8080' でリッスンします => [http://localhost:8080](http://127.0.0.1:8080)。\nこの設定を変更するには、次のファイルを作成して必要に応じて編集してください：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# ローカルネットワーク上のリッスンアドレス\naddress = \"127.0.0.1\"\n# 広域ネットワーク上のリッスンアドレス\n# address = \"0.0.0.0\"\n# リッスンするポート\nport = 8000\n```\n\n## おめでとうございます\n\nこれで、Yew 開発環境の設定が完了し、最初の Web アプリケーションを構築できました。\n\nこのアプリケーションを試してみて、さらに学習するために[サンプル](./examples.mdx)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'エディタの設定'\ndescription: 'コードエディタの設定'\n---\n\n:::important 改善ドキュメント\n異なるエディタを使用していますか？おすすめがあれば、選択したエディタの説明を自由に追加してください。\n:::\n\n## コンポーネント作成のためのテンプレートを追加\n\n### JetBrains IDEs\n\n1. ナビゲーションバーから順に File | Settings | Editor | Live Templates をクリックします。\n2. Rust を選択し、+ アイコンをクリックして新しい Live Template を追加します。\n3. 必要に応じて名前と説明を入力します。\n4. 以下のコードスニペットをテンプレートテキスト部分に貼り付けます。\n5. 右下の適用範囲を変更し、Rust > Item > Module を選択します。\n\n関数型コンポーネントの場合、以下のテンプレートを使用します。\n\n- (オプション) 変数を編集し、`tag` に適切なデフォルト値（例：\"div\"）を設定します。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n構造体コンポーネントの場合、以下のより複雑なテンプレートを使用できます。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. ナビゲーションバーから順に File > Preferences > User Snippets をクリックします。\n2. 設定言語として Rust を選択します。\n3. 以下の JSON ファイルにコードスニペットを追加します。\n\n````json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n## `html!` マクロのサポート\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 拡張機能\n\n> これは**進行中の**、**コミュニティが維持している**プロジェクトです！[詳細を確認し、関連するバグ報告/問題/質問を直接拡張機能のリポジトリに送信してください](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 拡張機能は [VSC Marketplace で見つけることができます](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)、シンタックスハイライト、リネーム、ホバーなどの機能を提供します。\n\nEmmet サポートは直接使用できるはずですが、できない場合は `settings.json` ファイルを編集してください：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n````\n\n### Neovim\n\n#### Lazyvim\n\n> 以下の設定は [LazyVim](https://www.lazyvim.org) 設定および lazy.vim プラグインに適用されます。`lua/plugins/nvim-lspconfig.lua` にファイルを作成するか、既存の `lspconfig` を更新してください：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/getting-started/examples.mdx",
    "content": "---\ntitle: '例'\n---\n\nYew リポジトリには多くの[例]（メンテナンス状態はさまざま）があります。\nフレームワークのさまざまな機能を理解するために、それらを参照することをお勧めします。\n無視されがちで助けが必要な場合に備えて、プルリクエストや問題も歓迎します ♥️。\n\n詳細については、[README] を参照してください。\n\n:::note\nほとんどの例には、https://examples.yew.rs/< example_name > で見つけることができるオンラインデプロイがあります。\nそれぞれのサブフォルダーの README ページでバッジをクリックして、オンラインデモに移動します。\n:::\n\n[例のリスト]: https://github.com/yewstack/yew/tree/master/examples\n[例のドキュメント README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/getting-started/introduction.mdx",
    "content": "---\ntitle: '始めに'\n---\n\nYew アプリケーションをコンパイル、ビルド、パッケージ、およびデバッグするためにいくつかのツールが必要です。最初に、[Trunk](https://trunkrs.dev/) を使用することをお勧めします。Trunk は Rust 用の WASM Web アプリケーションパッケージツールです。\n\n## Rust のインストール\n\nRust をインストールするには、[公式の手順](https://www.rust-lang.org/tools/install) に従ってください。\n\n:::important\nYew がサポートする最低 Rust バージョン（MSRV）は `1.84.0` です。古いバージョンではコンパイルできません。`rustup show`（「active toolchain」の下）または `rustc --version` を使用してツールチェーンのバージョンを確認できます。ツールチェーンを更新するには、`rustup update` を実行してください。\n:::\n\n## WebAssembly ターゲットのインストール\n\nRust は異なる「ターゲット」（例えば異なるプロセッサ）に対してソースコードをコンパイルできます。ブラウザベースの WebAssembly 用のコンパイルターゲットは `wasm32-unknown-unknown` と呼ばれます。以下のコマンドは、開発環境に WebAssembly ターゲットを追加します。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Trunk のインストール\n\nTrunk は、デプロイとパッケージ管理に推奨されるツールであり、ドキュメントやサンプル全体で使用されています。\n\n```shell\n# 注意：これはすべての内容をゼロからコンパイルするため、インストールに時間がかかる場合があります\n# Trunk は多くの主要なパッケージマネージャーに対して事前構築されたバイナリを提供しています\n# 詳細については、https://trunkrs.dev/#install を参照してください\ncargo install --locked trunk\n```\n\n### 他のオプション\n\nTrunk の他にも、Yew アプリケーションをパッケージ化するための他のオプションがあります。以下のオプションのいずれかを試してみることをお勧めします：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/)（まだ初期開発段階です）\n\n## 次のステップ\n\n開発環境の設定が完了したら、ドキュメントの読み進めを続けることができます。実践を通じて学ぶのが好きな方は、[チュートリアル](../tutorial)をチェックすることをお勧めします。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nYew に CSS サポートを統合する最良の方法についての議論は、こちらで見つけることができます：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\nここには、Yew に CSS サポートを統合する最良の方法についての多くの議論が含まれています。\n\n現在、私たちが採用している方法は、開発者が最も人気のあるシステムを採用する前に多くのシステムを構築することを奨励することです。\n\nコミュニティは現在、プロジェクトにスタイルを追加するためのいくつかのプロジェクトを開発しています。以下はその一部です：\n\n#### コンポーネントライブラリ\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - JavaScript 依存なしの Yew スタイルフレームワーク。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - マテリアルデザインコンポーネント。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS コンポーネント。\n- [Yewtify](https://github.com/yewstack/yewtify) – Yew で Vuetify フレームワークの機能を実現。\n\n#### スタイルソリューション\n\n- [stylist](https://github.com/futursolo/stylist-rs) - WebAssembly アプリケーション用の CSS-in-Rust スタイルソリューション。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind ユーティリティクラス。\n\n:::important ドキュメントの改善\nYew にスタイルを追加するプロジェクトを開発している場合は、このリストに自分を追加する PR を提出してください！\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/more/debugging.mdx",
    "content": "---\ntitle: 'デバッグ'\n---\n\n## パニック (Panics)\n\nYew はブラウザのコンソールにパニックログを自動的に出力します。\n\n## コンソールログ\n\nJavaScript では、`console.log()` を使用してブラウザのコンソールに出力します。以下は Yew のいくつかのオプションです。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` クレートは [`log`](https://crates.io/crates/log) クレートと統合されており、ログレベル、ソース行、ファイル名をブラウザのコンソールに送信します。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nこのクレートは Gloo の一部で、ブラウザ API の Rust ラッパーを提供します。`log!` マクロは `JsValue` を直接受け入れることができ、`wasm_logger` よりも使いやすいです。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` は [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) と一緒に使用でき、メッセージをブラウザのコンソールに出力します。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## コンポーネントライフサイクルのデバッグ\n\n[`tracing`](https://crates.io/crates/tracing) は、コンポーネントのライフサイクルに関連するイベント情報を収集するために使用できます。`tracing` には `log` サポートの機能フラグもあり、`wasm-logger` とうまく統合できます。\n\n[コンパイル時フィルタ](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) は、詳細度を調整したりログ記録を無効にしたりするために使用できます。これにより、より小さな Wasm ファイルが生成されるはずです。\n\n## ソースマップ (Source Maps)\n\n[ソースマップ](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) をサポートするいくつかの方法がありますが、いくつかの設定が必要です。\n\n## 過去の記事\n\n以下は、Rust における WebAssembly デバッグの現状に関する過去の記事です。興味深い読み物かもしれません。\n\n\\[2019 年 12 月\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> これらの作業にはまだ多くのことが残されています。例えば、ツールの面では、Emscripten（Binaryen）と wasm-pack（wasm-bindgen）は、それらが実行する変換に対して DWARF 情報を更新することをまだサポートしていません。\n\n\\[2020 年\\] [Rust Wasm デバッグガイド](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 残念ながら、WebAssembly のデバッグ機能はまだ未成熟です。ほとんどの Unix システムでは、[DWARF](http://dwarfstd.org/) が実行中のプログラムのソースレベルの検査に必要な情報をエンコードするために使用されますが、Windows では同様の情報をエンコードする代替フォーマットがあります。しかし、現在のところ、WebAssembly には対応するフォーマットがありません。\n\n\\[2019 年\\] [Rust Wasm ロードマップ](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> デバッグは難しいです。なぜなら、多くの状況がこの作業グループの管理下にないからです。これは、WebAssembly の標準化機関やブラウザ開発者ツールを実装する人々に依存しています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/more/deployment.mdx",
    "content": "---\ntitle: 'デプロイ'\ndescription: 'Yew アプリケーションのデプロイ'\n---\n\nYew アプリケーションをサーバーにデプロイする準備ができたら、いくつかのデプロイオプションがあります。\n\n`trunk build --release` は、リリースモードでアプリケーションをビルドします。HTTP サーバーを設定して、サイトにアクセスしたときに `index.html` を提供し、静的パス（例：`index_<hash>.js` および `index_bg_<hash>.wasm`）のリクエストに対して trunk が生成した dist ディレクトリから適切なコンテンツを提供する必要があります。\n\n:::important `trunk serve --release` について\n`trunk serve --release` を使用してアプリケーションを提供しないでください。\nこれは開発中にリリースビルドをテストするためだけに使用されるべきです。\n:::\n\n## サーバー設定\n\n### `index.html` をフォールバックとして提供する\n\nアプリケーションが [Yew ルーター](concepts/router.mdx) を使用している場合、存在しないファイルへのリクエスト時にサーバーが `index.html` を返すように設定する必要があります。\n\nYew ルーターを使用するアプリケーションは [シングルページアプリケーション (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA) として構築されています。ユーザーが実行中のクライアントから URL にナビゲートすると、ルーターが URL を解釈してそのページにルーティングします。\n\nしかし、ページをリフレッシュしたり、アドレスバーに URL を入力したりすると、これらの操作は実行中のアプリケーションではなく、ブラウザー自体によって処理されます。ブラウザーはその URL を直接サーバーにリクエストし、ルーターをバイパスします。誤って設定されたサーバーは 404 - 見つかりません 状態を返します。\n\n`index.html` を返すことで、アプリケーションは通常通りにロードされ、ルーターがルート `/show/42` を認識して適切なコンテンツを表示するまで、リクエストが `/` であるかのように動作します。\n\n### Web Assembly リソースに正しい MIME タイプを設定する\n\nWASM ファイルは `application/wasm` MIME タイプで [Content-Type ヘッダー](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) を設定する必要があります。\n\nほとんどのサーバーとホスティングサービスはデフォルトでこれを行います。サーバーがこれを行わない場合は、そのドキュメントを参照してください。ほとんどの Web ブラウザーでは、誤った MIME タイプは次のようなエラーを引き起こします：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 相対パスのビルド\n\nデフォルトでは、trunk はサイトが `/` で提供されると仮定し、それに応じてサイトをビルドします。この動作は、`index.html` ファイルに `<base data-trunk-public-url />` を追加することで上書きできます。Trunk はこのタグを書き換えて、`--public-url` に渡された値を含めます。Yew ルーターは `<base />` の存在を自動的に検出し、適切に処理します。\n\n## 環境変数を使用して動作をカスタマイズする\n\n通常、環境変数を使用してビルド環境をカスタマイズします。アプリケーションがブラウザで実行されるため、実行時に環境変数を読み取ることはできません。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) マクロは、コンパイル時に環境変数の値を取得できます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/more/roadmap.mdx",
    "content": "---\ntitle: 'ロードマップ'\ndescription: 'Yew フレームワークの計画機能ロードマップ'\n---\n\n## 優先順位\n\nフレームワークの今後の機能と重点の優先順位はコミュニティによって決定されます。\n2020 年春に、プロジェクトの方向性に関するフィードバックを収集するために開発者調査を実施しました。\n調査の概要は [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) で確認できます。\n\n:::note\nすべての主要なイニシアチブのステータスは Yew Github の [プロジェクトボード](https://github.com/yewstack/yew/projects) で追跡できます。\n:::\n\n## 重点\n\n1. 最も人気のある機能\n2. プロダクションレディ\n3. ドキュメント\n4. 痛点\n\n### 最も人気のある機能\n\n1. [関数コンポーネント](https://github.com/yewstack/yew/projects/3)\n2. [コンポーネントライブラリ](https://github.com/yewstack/yew/projects/4)\n3. より良い状態管理\n4. [サーバーサイドレンダリング](https://github.com/yewstack/yew/projects/5)\n\n### プロダクションレディに必要な問題\n\n- Yew のテストカバレッジを向上させる\n- バイナリサイズを小さくする\n- [パフォーマンスベンチマーク](https://github.com/yewstack/yew/issues/5)\n\n### ドキュメント\n\n- チュートリアルを作成する\n- プロジェクト設定を簡素化する\n\n### 痛点\n\n- [コンポーネントテンプレート](https://github.com/yewstack/yew/issues/830)\n- [エージェント](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/more/testing.mdx",
    "content": "---\ntitle: 'アプリケーションのテスト'\ndescription: 'アプリケーションをテストする'\n---\n\n:::info\nコンポーネントのテストをより簡単にするために努力していますが、現在進行中です。\n\n[浅いレンダリング](https://github.com/yewstack/yew/issues/1413) のサポートは GitHub リポジトリで見つけることができます。\n:::\n\n## スナップショットテスト\n\nYew はコンポーネントのスナップショットテストを容易にするために `yew::tests::layout_tests` モジュールを提供しています。\n\n:::important ドキュメントの改善\nスナップショットテストのドキュメントを改善するための助けが必要です。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM ワーキンググループは [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) というクレートを維持しています。\nこれにより、組み込みの `#[test]` プロシージャマクロに似た方法でブラウザ内でテストを実行できます。\nこのモジュールの詳細については、[Rust Wasm ワーキンググループのドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/tutorial/index.mdx",
    "content": "---\ntitle: 'チュートリアル'\nslug: /tutorial\n---\n\n## 紹介\n\nこの実践チュートリアルでは、Yew を使用して Web アプリケーションを構築する方法を学びます。\n**Yew** は、[WebAssembly](https://webassembly.org/) を使用してフロントエンド Web アプリケーションを構築するためのモダンな [Rust](https://www.rust-lang.org/) フレームワークです。\nYew は Rust の強力な型システムを活用し、再利用可能で保守しやすく、良好に構造化されたアーキテクチャを奨励します。\nRust の [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html) と呼ばれるライブラリのエコシステムは、状態管理などの一般的なパターンのためのコンポーネントを提供します。\nRust のパッケージマネージャー [Cargo](https://doc.rust-lang.org/cargo/) を使用すると、Yew などの多くの crate を [crates.io](https://crates.io) から利用できます。\n\n### 構築する内容\n\nRustconf は、Rust コミュニティが毎年開催する星間集会です。\nRustconf 2020 には多くの講演があり、大量の情報が提供されました。\nこの実践チュートリアルでは、他の Rustaceans がこれらの講演を理解し、1つのページから視聴できるようにする Web アプリケーションを構築します。\n\n## セットアップ\n\n### 前提条件\n\nこのチュートリアルは、Rust に精通していることを前提としています。Rust の初心者である場合、無料の [Rust 本](https://doc.rust-lang.org/book/ch00-00-introduction.html) は初心者にとって素晴らしい出発点であり、経験豊富な Rust 開発者にとっても優れたリソースです。\n\n最新バージョンの Rust がインストールされていることを確認するには、`rustup update` を実行するか、[Rust をインストール](https://www.rust-lang.org/tools/install) します。\n\nRust をインストールした後、Cargo を使用して以下のコマンドを実行し、`trunk` をインストールします：\n\n```bash\ncargo install trunk\n```\n\nWASM のビルドターゲットも追加する必要があります。次のコマンドを実行します：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### プロジェクトの設定\n\nまず、新しい cargo プロジェクトを作成します：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nRust 環境が正しく設定されていることを確認するために、cargo ビルドツールを使用して初期プロジェクトを実行します。\nビルドプロセスの出力に続いて、期待される \"Hello, world!\" メッセージが表示されるはずです。\n\n```bash\ncargo run\n```\n\n## 最初の静的ページ\n\nこのシンプルなコマンドラインアプリケーションを基本的な Yew Web アプリケーションに変換するために、いくつかの変更が必要です。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\nアプリケーションを構築するだけの場合は、`csr` 特性のみが必要です。これにより、`Renderer` とクライアントサイドレンダリングに関連するすべてのコードが有効になります。\n\nライブラリを作成している場合は、この特性を有効にしないでください。クライアントサイドレンダリングロジックがサーバーサイドレンダリングパッケージに含まれてしまいます。\n\nテストやサンプルのために Renderer が必要な場合は、`dev-dependencies` で有効にするべきです。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nそれでは、プロジェクトのルートディレクトリに `index.html` を作成しましょう。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 開発サーバーの起動\n\n以下のコマンドを実行して、アプリケーションをビルドし、ローカルで提供します。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n`--open` オプションを削除して、`trunk serve` を実行した後にデフォルトのブラウザを開かないようにします。\n:::\n\nTrunk は、ソースコードファイルを変更するたびにアプリケーションをリアルタイムで再構築します。\nデフォルトでは、サーバーはアドレス '127.0.0.1' のポート '8080' でリッスンします => [http://localhost:8080](http://127.0.0.1:8080)。\nこの設定を変更するには、次のファイルを作成して必要に応じて編集します：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# ローカルネットワーク上のリッスンアドレス\naddress = \"127.0.0.1\"\n# 広域ネットワーク上のリッスンアドレス\n# address = \"0.0.0.0\"\n# リッスンするポート\nport = 8000\n```\n\nもし興味があれば、`trunk help` および `trunk help <subcommand>` を実行して、進行中のプロセスの詳細についてさらに学ぶことができます。\n\n### おめでとうございます\n\nこれで、Yew 開発環境を正常にセットアップし、最初の Yew Web アプリケーションを構築しました。\n\n## HTML の構築\n\nYew は Rust のプロシージャルマクロを利用しており、JSX（JavaScript の拡張で、JavaScript 内で HTML に似たコードを書くことができる）に似た構文を提供して、マークアップを作成します。\n\n### クラシック HTML への変換\n\n私たちのウェブサイトがどのように見えるかについての良いアイデアが既にあるので、単純にドラフトを `html!` と互換性のある表現に変換することができます。シンプルな HTML を書くことに慣れているなら、`html!` でマークアップを書くのに問題はないはずです。このマクロは HTML といくつかの違いがあることに注意してください：\n\n1. 式は中括弧（`{ }`）で囲む必要があります。\n2. ルートノードは1つだけでなければなりません。コンテナにラップせずに複数の要素を持ちたい場合は、空のタグ/フラグメント（`<> ... </>`）を使用できます。\n3. 要素は正しく閉じる必要があります。\n\nレイアウトを構築したいので、元の HTML は次のようになります：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nそれでは、この HTML を `html!` に変換しましょう。次のコードスニペットを `app` 関数の本体に入力（またはコピー/ペースト）して、関数が `html!` の値を返すようにします。\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\nブラウザページをリフレッシュすると、次の出力が表示されるはずです：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### マークアップ内でRustの構造を使用する\n\nRustでマークアップを書く大きな利点の1つは、マークアップ内でRustのすべての利点を享受できることです。\n今では、HTML内にビデオリストをハードコーディングするのではなく、それらを `Vec` の `Video` 構造体として定義します。\nデータを保持するために、`main.rs` または選択した任意のファイルにシンプルな `struct` を作成します。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n次に、この構造体のインスタンスを `app` 関数内で作成し、ハードコーディングされたデータの代わりにそれらを使用します：\n\n```rust\nuse website_test::tutorial::Video; // 自分のパスに置き換えてください\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\nそれらを表示するために、`Vec` を `Html` に変換する必要があります。これを実現するには、イテレータを作成し、それを `html!` にマッピングして `Html` として収集します：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\nリスト項目にキーを使用することで、Yew はリスト内のどの項目が変更されたかを追跡し、より高速な再レンダリングを実現できます。[リストには常にキーを使用することをお勧めします](/concepts/html/lists.mdx#keyed-lists)。\n::\n\n最後に、データから作成された `Html` を使用してハードコーディングされたビデオリストを置き換える必要があります：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## コンポーネント\n\nコンポーネントは Yew アプリケーションの構成要素です。コンポーネントを組み合わせることで（他のコンポーネントで構成されることもあります）、アプリケーションを構築します。再利用可能性を考慮してコンポーネントを構築し、それらを汎用的に保つことで、コードやロジックを繰り返すことなく、アプリケーションの複数の部分でそれらを使用できるようになります。\n\nこれまで使用してきた `app` 関数は `App` と呼ばれるコンポーネントであり、「関数コンポーネント」と呼ばれます。\n\n1. 構造体コンポーネント\n2. 関数コンポーネント\n\nこのチュートリアルでは、関数コンポーネントを使用します。\n\nでは、`App` コンポーネントをより小さなコンポーネントに分割しましょう。まず、ビデオリストを独自のコンポーネントに抽出します。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n`VideosList` 関数コンポーネントのパラメータに注意してください。関数コンポーネントは1つの引数しか受け取らず、その引数は \"props\"（\"properties\" の略）を定義します。Props は親コンポーネントから子コンポーネントにデータを渡すために使用されます。この場合、`VideosListProps` は props を定義する構造体です。\n\n:::important\nprops に使用される構造体は `Properties` を派生実装する必要があります。\n:::\n\n上記のコードをコンパイルするために、`Video` 構造体を次のように変更する必要があります：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n次に、`VideosList` コンポーネントを使用するように `App` コンポーネントを更新できます。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nブラウザウィンドウを確認することで、リストが期待通りにレンダリングされているかどうかを検証できます。リストのレンダリングロジックをそのコンポーネントに移動しました。これにより、`App` コンポーネントのソースコードが短くなり、読みやすく理解しやすくなりました。\n\n### アプリケーションをインタラクティブにする\n\nここでの最終目標は、選択したビデオを表示することです。そのためには、`VideosList` コンポーネントがビデオを選択したときに親コンポーネントに「通知」する必要があります。これは `Callback` を使用して行います。この概念は「ハンドラの伝播」と呼ばれます。props を変更して `on_click` コールバックを受け取るようにします：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n次に、選択したビデオをコールバックに渡すように `VideosList` コンポーネントを変更します。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n次に、`VideosList` の使用を変更してそのコールバックを渡す必要があります。しかし、その前に、新しいコンポーネント `VideoDetails` を作成し、ビデオがクリックされたときに表示されるようにします。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n次に、`App` コンポーネントを変更して、ビデオが選択されたときに `VideoDetails` コンポーネントを表示するようにします。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n今は `use_state` について心配する必要はありません。後でこの問題に戻ります。リストデータを `{ for details }` で抽出するテクニックに注目してください。\n`Option<_>` は `Iterator` を実装しているので、特殊な `{ for ... }` 構文を使用して `Iterator` が返す唯一の要素を順番に表示することができます。これは [`html!` マクロ](concepts/html/lists) によってサポートされています。\n\n### 状態の処理\n\n以前に使用した `use_state` を覚えていますか？それは \"フック\" と呼ばれる特殊な関数です。フックは関数コンポーネントのライフサイクルに \"フック\" して操作を実行するために使用されます。このフックや他のフックについては[こちら](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)で詳しく学ぶことができます。\n\n:::note\n構造体コンポーネントは異なる動作をします。これらについては[ドキュメント](advanced-topics/struct-components/introduction.mdx)を参照してください。\n:::\n\n## データの取得（外部 REST API の使用）\n\n実際のアプリケーションでは、データは通常ハードコーディングされているのではなく、API から取得されます。外部ソースからビデオリストを取得してみましょう。そのためには、以下のクレートを追加する必要があります：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  fetch 呼び出しを行うために使用します。\n- [`serde`](https://serde.rs) とその派生特性\n  JSON 応答をデシリアライズするために使用します。\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  Rust の Future を Promise として実行するために使用します。\n\n`Cargo.toml` ファイルの依存関係を更新しましょう：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n依存関係を選択する際には、それらが `wasm32` と互換性があることを確認してください！そうでない場合、アプリケーションを実行することはできません。\n:::\n\n`Deserialize` 特性を派生するように `Video` 構造体を更新します：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n最後のステップとして、ハードコーディングされたデータを使用するのではなく、fetch リクエストを行うように `App` コンポーネントを更新する必要があります。\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\nここでは `unwrap` を使用していますが、これはデモアプリケーションのためです。実際のアプリケーションでは、[適切なエラーハンドリング](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)を行うことをお勧めします。\n:::\n\nさて、ブラウザを確認して、すべてが期待通りに動作しているかを確認しましょう……CORS の問題がなければ。これを解決するために、プロキシサーバーが必要です。幸いなことに、trunk はこの機能を提供しています。\n\nこれらの行を更新します：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n次に、以下のコマンドを使用してサーバーを再起動します：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nページをリフレッシュすると、すべてが期待通りに動作するはずです。\n\n## まとめ\n\nおめでとうございます！外部 API からデータを取得し、ビデオリストを表示する Web アプリケーションを作成しました。\n\n## 次に\n\nこのアプリケーションは、完璧または有用になるまでにはまだ長い道のりがあります。このチュートリアルを完了した後、より高度なトピックを探求するための出発点として使用できます。\n\n### スタイル\n\n私たちのアプリケーションは非常に見栄えが悪いです。CSS やその他のスタイルがありません。残念ながら、Yew は組み込みのスタイルコンポーネントを提供していません。スタイルシートを追加する方法については、[Trunk のアセット](https://trunkrs.dev/assets/)を参照してください。\n\n### さらなる依存ライブラリ\n\n私たちのアプリケーションは、非常に少ない外部依存関係を使用しています。使用できる多くのクレートがあります。詳細については、[外部ライブラリ](/community/external-libs)を参照してください。\n\n### Yew についてもっと知る\n\n私たちの[公式ドキュメント](../getting-started/introduction.mdx)を読んでください。多くの概念についてより詳細に説明しています。Yew API についてもっと知りたい場合は、[API ドキュメント](https://docs.rs/yew)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.22.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.22\",\n    \"description\": \"The label for version 0.22\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Function Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Intro With Basic Web Technologies\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew mostly operates on the idea of keeping everything that a reusable piece of UI may need, in one place - rust files. But also seeks to stay close to the original look of the technology. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/children.mdx",
    "content": "---\ntitle: '子コンポーネント'\n---\n\n:::caution\n\n`Children` をチェックおよび操作すると、アプリケーションで驚くべきかつ説明が難しい動作が発生することがよくあります。これにより、エッジケースが発生し、通常は予期しない結果が生じる可能性があります。`Children` を操作しようとする場合は、他の方法を検討する必要があります。\n\nYew は、子コンポーネントのプロパティの型として `Html` を使用することをサポートしています。`Children` または `ChildrenRenderer` が必要ない場合は、子コンポーネントとして `Html` を使用することをお勧めします。これは `Children` の欠点がなく、パフォーマンスのオーバーヘッドも低くなります。\n\n:::\n\n## 一般的な使用法\n\n_ほとんどの場合、_ コンポーネントに子コンポーネントを持たせる場合、子コンポーネントの型を気にする必要はありません。この場合、以下の例で十分です。\n\n````rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n\n## 高度な使用法\n\n### 型指定された子コンポーネント\n\n特定のタイプのコンポーネントを子コンポーネントとして渡したい場合は、`yew::html::ChildrenWithProps<T>` を使用できます。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n````\n\n## プロパティを持つネストされた子コンポーネント\n\nコンポーネントがその子コンポーネントを型指定している場合、ネストされたコンポーネントのプロパティにアクセスして変更することができます。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 列挙型の子コンポーネント\n\nもちろん、時には子コンポーネントをいくつかの異なるコンポーネントに制限する必要がある場合があります。そのような場合には、Yewについてさらに深く理解する必要があります。\n\nここでは、より良いエルゴノミクスを提供するために [`derive_more`](https://github.com/JelteF/derive_more) を使用しています。使用したくない場合は、各バリアントに対して手動で `From` を実装することができます。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 現在、`Into<Html>` を実装して、yew が `Item` をどのようにレンダリングするかを知ることができるようにします。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### オプションの型の子コンポーネント\n\n特定の型の単一のオプションの子コンポーネントを持つこともできます：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... ページ内容\n            </div>\n        }\n    }\n}\n\n// ページコンポーネントはサイドバーを含むかどうかを選択できます：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // サイドバーを含むページ\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // サイドバーを含まないページ\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## さらに読む\n\n- このパターンの実際の例については、yew-router のソースコードを参照してください。より高度な例については、yew リポジトリの[関連する例のリスト](https://github.com/yewstack/yew/tree/master/examples/nested_list)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '仕組み'\ndescription: 'フレームワークの低レベルの詳細について'\n---\n\n# 基本ライブラリの内部詳細\n\n## `html!` マクロの内部\n\n`html!` マクロは、HTMLに似たカスタム構文で記述されたコードを有効なRustコードに変換します。このマクロを使用することはYewアプリケーションの開発に必須ではありませんが、推奨されています。このマクロが生成するコードはYewのパブリックライブラリAPIを使用しており、希望すれば直接使用することもできます。いくつかのメソッドは意図的に文書化されていないため、誤用を避けるために注意が必要です。`yew-macro`の各更新により、生成されるコードはより効率的になり、`html!`構文をほとんど（または全く）変更することなく破壊的な変更を処理できるようになります。\n\n`html!` マクロを使用すると、宣言的なスタイルでコードを記述できるため、UIレイアウトコードはページのHTMLに非常に似たものになります。アプリケーションがよりインタラクティブになり、コードベースが大きくなるにつれて、この方法はますます有用になります。DOM 操作のすべてのコードを手動で記述するのに比べて、マクロがこれらすべてを処理してくれます。\n\n`html!` マクロの使用は非常に魔法のように感じるかもしれませんが、隠すべきものは何もありません。その仕組みに興味がある場合は、プログラム内の `html!` マクロ呼び出しを展開してみてください。`cargo expand` という便利なコマンドがあり、Rustマクロの展開を確認できます。`cargo expand` はデフォルトで `cargo` に含まれていないため、まだインストールしていない場合は `cargo install cargo-expand` を使用してインストールする必要があります。[Rust-Analyzer](https://rust-analyzer.github.io/) も[IDEからマクロ出力を取得するメカニズム](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)を提供しています。\n\n`html!` マクロの出力は通常非常に簡潔です！これは特徴です：機械生成のコードは時々アプリケーション内の他のコードと衝突することがあります。問題を防ぐために、`proc_macro` は「衛生」ルールに従っています。いくつかの例を以下に示します：\n\n1. Yewパッケージを正しく参照するために、マクロ生成コードでは `::yew::<module>` を使用し、直接 `yew::<module>` を使用しません。これは `::alloc::vec::Vec::new()` を呼び出すのと同じ理由です。\n2. トレイトメソッド名の衝突を避けるために、`<Type as Trait>` を使用して正しいトレイトメンバーを使用していることを確認します。\n\n## 仮想 DOM とは？\n\nDOM（「ドキュメントオブジェクトモデル」）は、ブラウザによって管理されるHTMLコンテンツの表現です。「仮想」 DOM は、単にメモリ内の DOM のコピーです。仮想 DOM を管理することで、メモリのオーバーヘッドが増加しますが、ブラウザAPIの使用を回避または遅延させることでバッチ処理と高速な読み取りを実現できます。\n\nメモリ内に DOM のコピーを持つことは、宣言的UIを使用するライブラリの使用を促進するのに役立ちます。ユーザーイベントに基づいて DOM を変更するための特定のコードが必要な場合とは異なり、ライブラリは一般的な方法を使用して DOM の「差分」を行うことができます。Yewコンポーネントが更新され、そのレンダリング方法を変更したい場合、Yewライブラリは仮想 DOM の2番目のコピーを構築し、現在画面上に表示されている内容をミラーリングする仮想 DOM と直接比較します。両者の「差分」は増分更新に分解され、ブラウザAPIと共に適用されます。更新が適用されると、古い仮想 DOM のコピーは破棄され、新しいコピーが将来の差分チェックのために保存されます。\n\nこの「差分」アルゴリズムは、時間の経過とともに最適化され、複雑なアプリケーションのパフォーマンスを向上させることができます。YewアプリケーションはWebAssemblyを介して実行されるため、Yewは将来的により複雑なアルゴリズムを採用する上で競争力を持つと信じています。\n\nYewの仮想 DOM はブラウザの DOM と完全に一対一対応しているわけではありません。DOM 要素を整理するための「リスト」や「コンポーネント」も含まれています。リストは単に要素の順序付きリストである場合もありますが、より強力な場合もあります。各リスト要素に「キー」注釈を追加することで、アプリケーション開発者はリストが変更されたときに差分更新の計算に必要な作業量を最小限に抑えるための追加の最適化をYewに提供できます。同様に、コンポーネントは再レンダリングが必要かどうかを示すカスタムロジックを提供し、パフォーマンスを向上させるのに役立ちます。\n\n## Yewスケジューラとコンポーネントスコープのイベントループ\n\n_貢献ドキュメント - `yew::scheduler` と `yew::html::scope` の仕組みを詳しく説明_\n\n## さらなる読み物\n\n- [Rustのマクロに関する詳細情報](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` に関する詳細情報](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` のAPIドキュメント](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'イミュータブルタイプ'\ndescription: 'Yew のイミュータブルデータ構造'\n---\n\n## イミュータブルタイプとは？\n\nこれらのタイプは、インスタンス化はできるが値を変更することはできないタイプです。値を更新するには、新しい値をインスタンス化する必要があります。\n\n## なぜイミュータブルタイプを使用するのですか？\n\nReact と同様に、プロパティは祖先から子孫に伝播されます。これは、各コンポーネントが更新されるたびにプロパティが存在する必要があることを意味します。したがって、プロパティは理想的には簡単にクローンできるべきです。これを実現するために、通常は `Rc` にラップします。\n\nイミュータブルタイプは、コンポーネント間でプロパティの値を低コストでクローンできるため、プロパティの値を保持するのに最適です。\n\n## 一般的なイミュータブルタイプ\n\nYew は `implicit-clone` クレートから以下のイミュータブルタイプの使用を推奨しています：\n\n- `IString`（Yew では `AttrValue` としてエイリアス化）- `String` の代わりに文字列用\n- `IArray<T>` - `Vec<T>` の代わりに配列・ベクター用\n- `IMap<K, V>` - `HashMap<K, V>` の代わりにマップ用\n\nこれらのタイプは参照カウント（`Rc`）または静的参照のいずれかであり、非常に安価にクローンできます。\n\n## さらに読む\n\n- [イミュータブルの例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '最適化とベストプラクティス'\nsidebar_label: Optimizations\ndescription: 'アプリケーションのパフォーマンスを最適化する'\n---\n\n## スマートポインタの使用\n\n**注意：このセクションで使用されている用語に混乱がある場合は、Rustのマニュアルにある[スマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)が役立ちます。**\n\n再レンダリング時に大量のデータをクローンしてpropsを作成するのを避けるために、スマートポインタを使用してデータ自体ではなくデータへの参照のみをクローンすることができます。propsや子コンポーネントに関連データの参照を渡すことで、データを変更する必要がある子コンポーネントでデータをクローンするのを避けることができます。`Rc::make_mut`を使用してデータをクローンし、変更するための可変参照を取得できます。\n\nこれにより、`Component::changed`でのpropの変更がコンポーネントの再レンダリングを必要とするかどうかを判断する際にさらに利点があります。これは、データの値ではなくポインタのアドレス（つまり、データがマシンメモリに格納されている場所）を比較できるためです。2つのポインタが同じデータを指している場合、それらが指しているデータの値は同じでなければなりません。逆は必ずしも真ではないことに注意してください！2つのポインタアドレスが異なる場合でも、基になるデータは同じである可能性があります。この場合、基になるデータを比較する必要があります。\n\nこの比較を行うには、`PartialEq`（データを比較する際に自動的に使用される等価演算子`==`）ではなく、`Rc::ptr_eq`を使用する必要があります。Rustのドキュメントには、`Rc::ptr_eq`に関する[詳細](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)があります。\n\nこの最適化は、`Copy`を実装していないデータ型に最も有用です。データを安価にコピーできる場合、それをスマートポインタの後ろに置く必要はありません。`Vec`、`HashMap`、`String`などのデータ集約型の構造体に対して、スマートポインタを使用することでパフォーマンスの向上が見込まれます。\n\nこの最適化は、子コンポーネントが値を更新しない場合に最も効果的であり、親コンポーネントがほとんど更新されない場合にさらに効果的です。これにより、`Rc<_>`は純粋なコンポーネントでpropsの値をラップするのに適した選択肢となります。\n\nただし、子コンポーネントでデータを自分でクローンする必要がない限り、この最適化は無駄であり、不要な参照カウントのコストを追加するだけです。Yewのpropsはすでに参照カウントされており、内部でデータのクローンは行われません。\n\n## レンダリング関数\n\nコードの可読性のために、`html!`の一部の繰り返しコードを専用の分割関数に移行することは通常意味があります。これにより、コードが読みやすくなり、インデントが減り、良いデザインパターンを奨励します。特に、複数の場所で呼び出すことができるこれらの関数を使用して、コード量を減らすことができます。\n\n## 純粋なコンポーネント\n\n純粋なコンポーネントは、その状態を変更せず、コンテンツを表示し、メッセージを通常の可変コンポーネントに伝播するコンポーネントです。これらは、`html!`マクロ内でコンポーネント構文（`<SomePureComponent />`）を使用する点でビュー関数とは異なり、実装に応じてメモ化される可能性があります（これは、一度関数が呼び出されると、その値が「保存」されることを意味し、同じパラメータで複数回呼び出された場合、その値を再計算する必要がなく、最初の関数呼び出しから保存された値を返すだけです）。Yewは内部でpropsを比較するため、propsが変更された場合にのみUIを再レンダリングします。\n\n## ワークスペースを使用してコンパイル時間を短縮する\n\nYewの最大の欠点は、コンパイルにかかる時間が長いことです。プロジェクトのコンパイルにかかる時間は、`html!`マクロに渡されるコードの量に関連しているようです。小規模なプロジェクトでは問題にならないようですが、大規模なアプリケーションでは、コンパイラがアプリケーションのために行う作業量を最小限に抑えるためにコードを複数のクレートに分割することが理にかなっています。\n\n1つの方法として、メインクレートがルーティング/ページ選択を処理し、各ページごとに異なるクレートを作成することが考えられます。各ページは異なるコンポーネントまたは`Html`を生成する大きな関数である可能性があります。アプリケーションの異なる部分を含むクレート間で共有されるコードは、プロジェクトが依存する別のクレートに格納できます。理想的には、すべてのコードを再コンパイルするのではなく、メインクレートと1つのページクレートのみを再コンパイルすることになります。最悪の場合、「共通」クレートで何かを編集した場合、すべての依存コードを再コンパイルする必要があり、元の状態に戻ります。\n\nメインクレートが重すぎる場合や、深くネストされたページ（例：別のページ上にレンダリングされるページ）を迅速に反復したい場合は、メインページの簡略化された実装を作成し、作業中のコンポーネントを追加でレンダリングするためにサンプルクレートを使用できます。\n\n## バイナリサイズの縮小\n\n- Rustコードの最適化\n- `cargo.toml`（リリースプロファイルの定義）\n- `wasm-opt` を使用してwasmコードを最適化\n\n**注意：バイナリサイズの縮小に関する詳細は、[Rust Wasmマニュアル](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)を参照してください。**\n\n### Cargo.toml\n\nリリースビルドをより小さくするために、`Cargo.toml`の`[profile.release]`セクションで利用可能な設定を使用して構成できます。\n\n```toml, title=Cargo.toml\n[profile.release]\n# バイナリサイズを小さくする\npanic = 'abort'\n# コード全体を最適化する（最適化は良くなるが、ビルド速度は遅くなる）\ncodegen-units = 1\n# サイズを最適化する（より積極的なアプローチ）\nopt-level = 'z'\n# サイズを最適化する\n# opt-level = 's'\n# プログラム全体の解析を使用してリンク時に最適化\nlto = true\n```\n\n### 開発版 Cargo 設定\n\nRust と cargo の実験的な開発版機能から追加の利点を得ることもできます。`trunk` の開発版ツールチェーンを使用するには、`RUSTUP_TOOLCHAIN=\"nightly\"` 環境変数を設定します。その後、`.cargo/config.toml` で不安定な rustc 機能を構成できます。不安定機能のドキュメント、特に[`build-std`]および[`build-std-features`]に関する部分を参照して、設定方法を確認してください。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# rust-srcコンポーネントが必要です。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不安定な機能のリスト]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n開発版のRustコンパイラには、[この例](https://github.com/yewstack/yew/issues/2696)のようなバグが含まれている可能性があるため、定期的に監視し調整する必要があります。これらの実験的なオプションを使用する際は注意が必要です。\n:::\n\n### wasm-opt\n\nさらに、`wasm` コードのサイズを最適化することができます。\n\nRust Wasm マニュアルには、Wasm バイナリファイルのサイズを縮小する方法に関するセクションがあります：[.wasm サイズの縮小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- `wasm-pack` を使用すると、デフォルトでリリースビルドの `wasm` コードが最適化されます\n- `wasm` ファイルに直接 `wasm-opt` を使用する\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### yew/examples/ の 'minimal' サンプルのビルドサイズ\n\n注意：`wasm-pack` は Rust と Wasm コードの最適化を組み合わせています。この例では、`wasm-bindgen` は Rust のサイズ最適化を行っていません。\n\n| ツールチェーン              | サイズ |\n| :-------------------------- | :----- |\n| wasm-bindgen                | 158KB  |\n| wasm-bindgen + wasm-opt -Os | 116KB  |\n| wasm-pack                   | 99 KB  |\n\n## さらに読む\n\n- [Rust マニュアルのスマート ポインターに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm マニュアルのコードサイズの縮小に関する章](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust プロファイルに関するドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'ポータル (Portals)'\ndescription: 'コンテンツをDOMツリー外のノードにレンダリングする'\n---\n\n## ポータルとは？\n\nポータル (Portal) は、子要素を親コンポーネントのDOM階層外のDOMノードにレンダリングする方法を提供します。`yew::create_portal(child, host)` は `Html` 値を返し、`child` を `host` 要素の子要素としてレンダリングしますが、親コンポーネントの階層下ではありません。\n\n## 使用方法\n\nポータルの典型的な用途には、モーダルダイアログやホバーカード、さらに技術的な用途として、要素の [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) の内容を制御すること、スタイルシートを周囲のドキュメントの `<head>` に添付すること、`<svg>` の中央の `<defs>` 要素に参照される要素を収集することなどがあります。\n\n`yew::create_portal` は低レベルの構成要素であることに注意してください。ライブラリはこれを使用してより高レベルのAPIを実装し、その後アプリケーションはこれらのAPIを使用できます。例えば、ここでは `children` を `yew` 以外の要素にレンダリングするシンプルなモーダルダイアログを示します。この要素は `id=\"modal_host\"` で識別されます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## イベント処理\n\nポータル内部の要素で発生するイベントは、仮想DOMのバブリングに従います。つまり、ポータルが要素の子要素としてレンダリングされる場合、その要素上のイベントリスナーは、ポータル内部から発生するイベントをキャプチャします。たとえポータルが実際のDOM内の無関係な位置にその内容をレンダリングしていてもです。\n\nこれにより、開発者は使用しているコンポーネントがポータルを使用して実装されているかどうかを気にする必要がなくなります。いずれにせよ、その子要素上で発生するイベントはバブリングします。\n\n既知の問題として、ポータルから **閉じた** シャドウルートへのイベントは2回分配されます。1回はシャドウルート内部の要素に対して、もう1回はホスト要素自体に対してです。**開いた** シャドウルートは正常に動作しますので、これが影響する場合は、いつでもバグレポートを提出してください。\n\n## さらなる読み物\n\n- [ポータルの例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: 'サーバーサイドレンダリング'\ndescription: 'Yewコンポーネントをサーバーサイドでレンダリングする。'\n---\n\n# サーバーサイドレンダリング (Server-Side Rendering)\n\nデフォルトでは、Yewコンポーネントはクライアントサイドでレンダリングされます。ユーザーがウェブサイトにアクセスすると、サーバーは実際のコンテンツを含まない骨組みのHTMLファイルとWebAssemblyパッケージをブラウザに送信します。すべてのコンテンツはクライアントサイドでWebAssemblyパッケージによってレンダリングされます。これをクライアントサイドレンダリングと呼びます。\n\nこの方法はほとんどのウェブサイトにとって有効ですが、いくつかの注意点があります：\n\n1. ユーザーはWebAssemblyパッケージがダウンロードされ、初期レンダリングが完了するまで何も表示されません。これにより、ネットワークが遅い場合にユーザーエクスペリエンスが悪化する可能性があります。\n2. 一部の検索エンジンは動的にレンダリングされたウェブページのコンテンツをサポートしておらず、サポートしている検索エンジンでも通常は動的なウェブサイトのランキングが低くなります。\n\nこれらの問題を解決するために、ウェブサイトをサーバーサイドでレンダリングすることができます。\n\n## 動作原理\n\nYewはページをサーバーサイドでレンダリングするための `ServerRenderer` を提供しています。\n\nYewコンポーネントをサーバーサイドでレンダリングするには、`ServerRenderer::<App>::new()` を使用してレンダラーを作成し、`renderer.render().await` を呼び出して `<App />` を `String` としてレンダリングします。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// この例が CI の WASM 環境で動作することを保証するために `flavor = \"current_thread\"` を使用しています。\n// マルチスレッドを使用したい場合は、デフォルトの `#[tokio::main]` マクロを使用できます。\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // プリント: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## コンポーネントのライフサイクル\n\nクライアントサイドレンダリングとは異なり、サーバーサイドレンダリング時のコンポーネントのライフサイクルは異なります。\n\nコンポーネントが最初に `Html` として正常にレンダリングされるまで、`use_effect`（および `use_effect_with`）以外のすべてのフックは正常に動作します。\n\n:::caution ブラウザインターフェースは利用できません！\n\n`web_sys` などのブラウザ関連のインターフェースは、サーバーサイドレンダリング時には利用できません。これらを使用しようとすると、アプリケーションがクラッシュします。このロジックは `use_effect` または `use_effect_with` に隔離する必要があります。これらはサーバーサイドレンダリング時には実行されないためです。\n\n:::\n\n:::danger 構造化コンポーネント\n\nサーバーサイドレンダリング時に構造化コンポーネントを使用することは可能ですが、クライアントサイドの安全なロジック（関数コンポーネントの `use_effect` フックなど）とライフサイクルイベントの間には明確な境界がなく、ライフサイクルイベントの呼び出し順序もクライアントとは異なります。\n\nさらに、構造化コンポーネントは、すべての子コンポーネントがレンダリングされ `destroy` メソッドが呼び出されるまでメッセージを受け取り続けます。開発者は、コンポーネントに渡される可能性のあるメッセージがブラウザインターフェースを呼び出すロジックにリンクされないようにする必要があります。\n\nサーバーサイドレンダリングをサポートするアプリケーションを設計する際は、特別な理由がない限り、関数コンポーネントを使用することをお勧めします。\n\n:::\n\n## サーバーサイドレンダリング中のデータ取得\n\nデータ取得はサーバーサイドレンダリングとハイドレーション（hydration）中の難点の一つです。\n\n従来の方法では、コンポーネントがレンダリングされるとすぐに利用可能になります（仮想DOMを出力してレンダリングします）。コンポーネントがデータを取得する必要がない場合、この方法は有効です。しかし、コンポーネントがレンダリング時にデータを取得しようとするとどうなるでしょうか？\n\n以前は、Yewにはコンポーネントがまだデータを取得しているかどうかを検出するメカニズムがありませんでした。データ取得クライアントは、初期レンダリング中に何が要求されたかを検出し、要求が完了した後に再レンダリングをトリガーするソリューションを実装する責任がありました。サーバーはこのプロセスを繰り返し、応答を返す前にレンダリング中に追加の保留中の要求がないことを確認します。\n\nこれは、コンポーネントを繰り返しレンダリングするため、CPUリソースを浪費するだけでなく、データクライアントは、サーバー側で取得したデータをハイドレーション中に利用可能にする方法を提供する必要があり、初期レンダリングで返される仮想DOMがサーバーサイドレンダリングのDOMツリーと一致することを保証する必要があります。これは実現が難しい場合があります。\n\nYewは、`<Suspense />` を使用してこの問題を解決する異なるアプローチを採用しています。\n\n`<Suspense />` は特別なコンポーネントで、クライアント側で使用する場合、コンポーネントがデータを取得（保留）している間にフォールバックUIを表示し、データ取得が完了した後に通常のUIに戻る方法を提供します。\n\nアプリケーションがサーバーサイドレンダリングされると、Yewはコンポーネントが保留状態でなくなるまで待機し、それを文字列バッファにシリアル化します。\n\nハイドレーション中、`<Suspense />` コンポーネント内の要素は、すべての子コンポーネントが保留状態でなくなるまでハイドレーションされません。\n\nこの方法により、開発者はサーバーサイドレンダリングに対応したクライアント非依存のアプリケーションを簡単に構築し、データ取得を行うことができます。\n\n## `<head>` タグのレンダリング\n\nSSR でよく必要とされるのは、クローラーやソーシャルプレビューが最初のロード時に正しいメタデータを参照できるよう、動的な `<head>` コンテンツ（`<title>`、`<meta>` など）をレンダリングすることです。\n\n`ServerRenderer` はコンポーネントツリー（通常はドキュメントの body 部分）のみをレンダリングし、`<head>` にはアクセスできません。そのため、head タグは **Yew の外部でサーバー側に**生成し、クライアントに送信する前に HTML テンプレートに埋め込む必要があります。\n\n[`ssr_router` サンプル](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) はこのパターンを示しています：サーバーはリクエスト URL からルートを判別し、適切な `<title>` および `<meta>` タグを生成して、Trunk が生成した `index.html` の `</head>` の前に挿入します。\n\n:::info\n\n完全に SSR 互換のサードパーティソリューションとして、[Bounce の `<Helmet/>` コンポーネント](https://docs.rs/bounce/latest/bounce/helmet/index.html) が利用できます。\n\n:::\n\n## サーバーサイドレンダリングハイドレーション（SSR Hydration）\n\nハイドレーションは、Yewアプリケーションをサーバー側で生成されたHTMLファイルに接続するプロセスです。デフォルトでは、`ServerRender` はハイドレーション可能なHTML文字列を出力し、追加情報を含んでハイドレーションを容易にします。`Renderer::hydrate` メソッドを呼び出すと、Yewは最初からレンダリングするのではなく、アプリケーションが生成した仮想DOMとサーバーレンダラーが生成したHTML文字列を調整します。\n\n:::caution\n\n`ServerRenderer` が作成したHTMLマークアップを正常にハイドレーションするためには、クライアントはSSRに使用されたレイアウトと完全に一致する仮想DOMレイアウトを生成する必要があります。要素を含まないコンポーネントも含めてです。特定の実装でのみ使用されるコンポーネントがある場合は、`PhantomComponent` を使用して追加のコンポーネントの位置を埋めることを検討してください。\n:::\n\n:::warning\n\nSSR出力（静的HTML）をブラウザが初期レンダリングした後、実際のDOMが期待されるDOMと一致する場合にのみ、ハイドレーションは成功します。HTMLが規格に準拠していない場合、ハイドレーションは失敗する可能性があります。ブラウザは不正なHTMLのDOM構造を変更する可能性があり、実際のDOMが期待されるDOMと異なることがあります。例えば、[`<tbody>` のない `<table>` がある場合、ブラウザはDOMに `<tbody>` を追加する可能性があります](https://github.com/yewstack/yew/issues/2684)。\n:::\n\n## ハイドレーション中のコンポーネントライフサイクル\n\nハイドレーション中、コンポーネントは作成後に2回連続してレンダリングされます。すべてのエフェクトは2回目のレンダリングが完了した後に呼び出されます。コンポーネントのレンダリング関数に副作用がないことを確認することが重要です。状態を変更したり、追加のレンダリングをトリガーしたりしないようにしてください。現在、状態を変更したり追加のレンダリングをトリガーしたりするコンポーネントがある場合は、それらを `use_effect` フックに移動してください。\n\nハイドレーション中、構造化コンポーネントを使用してサーバーサイドレンダリングを行うことができます。ビュー関数はレンダリング関数の前に複数回呼び出されます。レンダリング関数が呼び出されるまで、DOMは未接続と見なされ、`rendered()` メソッドが呼び出される前にレンダリングノードにアクセスすることを防ぐ必要があります。\n\n## 例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // body 要素の下のすべてのコンテンツをハイドレーションし、末尾の要素を削除します（存在する場合）。\n    renderer.hydrate();\n}\n```\n\n例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## シングルスレッドモード\n\nYewは `yew::LocalServerRenderer` を使用してシングルスレッドでのサーバーサイドレンダリングをサポートしています。このモードはWASIのようなシングルスレッド環境に適しています。\n\n```rust\n// `wasm32-wasip1` または `wasm32-wasip2` ターゲットを使用してビルドしてください。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n`wasm32-unknown-unknown` ターゲットを使用してSSRアプリケーションをビルドする場合、`not_browser_env` 機能フラグを使用して、Yew内部のブラウザ固有のAPIへのアクセスを無効にすることができます。これは、Cloudflare Workerのようなサーバーレスプラットフォームで非常に便利です。\n:::\n\n:::caution\n\nサーバーサイドレンダリングは現在実験的な機能です。バグを見つけた場合は、[GitHubで報告してください](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'コールバック関数 (Callbacks)'\n---\n\n## コールバック関数 (Callbacks)\n\nコールバック関数は、Yew でサービス、エージェント、および親コンポーネントと通信するために使用されます。内部的には、それらの型は `Rc` に包まれた `Fn` に過ぎず、クローンを許可します。\n\nそれらには `emit` 関数があり、その `<IN>` 型を引数として取り、それをターゲットが期待するメッセージに変換します。親コンポーネントのコールバック関数が子コンポーネントに props として提供される場合、子コンポーネントはその `update` ライフサイクルフックでコールバック関数の `emit` 関数を呼び出して、メッセージを親コンポーネントに送信できます。`html!` マクロで props として提供されるクロージャまたは関数は、自動的にコールバック関数に変換されます。\n\nシンプルなコールバック関数の使用例は次のようになります：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nこの関数を `callback` に渡す場合、常に1つの引数を持つ必要があります。例えば、`onclick` ハンドラは `MouseEvent` 型の引数を受け取る関数である必要があります。その後、ハンドラはコンポーネントにどのタイプのメッセージを送信するかを決定できます。このメッセージは無条件に次の更新サイクルにスケジュールされます。\n\n更新を引き起こす必要がないコールバック関数が必要な場合は、`batch_callback` を使用してください。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 関連例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高階コンポーネント'\n---\n\nいくつかの状況では、構造コンポーネントは特定の機能（例えば Suspense）を直接サポートしていないか、または特定の機能を使用するために大量のボイラープレートコードが必要です（例えば Context）。\n\nこのような場合、高階コンポーネントの関数コンポーネントを作成することをお勧めします。\n\n## 高階コンポーネントの定義\n\n高階コンポーネントは、新しい HTML を追加せず、他のコンポーネントをラップして追加機能を提供するコンポーネントです。\n\n### 例\n\nContext（コンテキスト）フックを使用し、それを構造コンポーネントに渡す例\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '紹介'\ndescription: 'Yew のコンポーネント'\n---\n\n## コンポーネントとは？\n\nコンポーネントは Yew の構成要素です。内部状態を管理し、要素を DOM にレンダリングできます。`Component` トレイトを実装することでコンポーネントを作成します。\n\n## コンポーネントマークアップの作成\n\nYew は仮想 DOM を使用して要素を DOM にレンダリングします。仮想 DOM ツリーは `html!` マクロを使用して構築できます。`html!` の構文は HTML に似ていますが、同じではありません。ルールもより厳格です。また、条件付きレンダリングやイテレータを使用したリストのレンダリングなどの強力な機能も提供します。\n\n:::info\n[`html!` マクロ、その使用方法、および構文についてさらに詳しく知る](concepts/html/introduction.mdx)\n:::\n\n## コンポーネントにデータを渡す\n\nYew コンポーネントは _props_ を使用して親コンポーネントと子コンポーネント間で通信します。親コンポーネントは任意のデータを props として子コンポーネントに渡すことができます。Props は HTML 属性に似ていますが、任意の Rust 型を props として渡すことができます。\n\n:::info\n[props についてさらに詳しく知る](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n親/子通信以外の通信には、[コンテキスト](../../concepts/contexts.mdx) を使用してください\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'ライフサイクル'\ndescription: 'コンポーネントとそのライフサイクルフック'\n---\n\n`Component` トレイトには、実装する必要がある多くのメソッドがあります。Yew はコンポーネントのライフサイクルのさまざまな段階でこれらのメソッドを呼び出します。\n\n## ライフサイクル\n\n:::important ドキュメントの改善\n`ドキュメントに貢献する：` [カスタムライフサイクルを持つコンポーネントの例を追加](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## ライフサイクルメソッド\n\n### Create\n\nコンポーネントが作成されるとき、それは親コンポーネントからプロパティを受け取り、それらは `create` メソッドに渡される `Context<Self>` に保存されます。これらのプロパティはコンポーネントの状態を初期化するために使用でき、\"link\" はコールバックを登録したり、コンポーネントにメッセージを送信したりするために使用できます。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体的な実装\n        }\n    }\n}\n```\n\n### View\n\n`view` メソッドは、コンポーネントがDOMにどのようにレンダリングされるべきかを記述することを可能にします。Rust関数を使用してHTMLに似たコードを書くことは非常に混乱する可能性があるため、Yewは`html!`マクロを提供しています。これにより、HTMLおよびSVGノードを宣言し（およびそれらに属性とイベントリスナーを追加し）、子コンポーネントを便利にレンダリングする方法が提供されます。このマクロは、ReactのJSXに似ています（プログラミング言語の違いを除いて）。一つの違いは、YewがSvelteのようなプロパティの簡略化された構文を提供している点です。ここでは、`{onclick}`とだけ書くことができ、`onclick={onclick}`と書く必要はありません。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n使用方法の詳細については、[html! ガイド](concepts/html/introduction.mdx) を参照してください。\n\n### Rendered\n\n`rendered` コンポーネントライフサイクルメソッドは、`view` が呼び出され、Yew がその結果を DOM にレンダリングした後、ブラウザがページを更新する前に呼び出されます。このメソッドは、コンポーネントが要素をレンダリングした後にのみ完了できる操作を実行したい場合に非常に便利です。また、`first_render` という名前のパラメーターがあり、この関数が最初のレンダリング時に呼び出されたか、後続のレンダリング時に呼び出されたかを判断するために使用できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nこのライフサイクルメソッドは実装する必要はなく、デフォルトでは何も実行しません。\n:::\n\n### Update\n\nコンポーネントとの通信は主にメッセージを通じて行われ、これらのメッセージは `update` ライフサイクルメソッドによって処理されます。これにより、コンポーネントはメッセージに基づいて自身を更新し、再レンダリングが必要かどうかを判断できます。メッセージはイベントリスナー、子コンポーネント、エージェント、サービス、またはフューチャーによって送信されることがあります。\n\n以下は `update` の実装例です：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 再レンダリング\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体的な実装\n        }\n    }\n\n}\n```\n\n### Changed\n\nコンポーネントは親コンポーネントによって再レンダリングされることがあります。この場合、新しいプロパティを受け取り、再レンダリングが必要になることがあります。この設計により、プロパティの値を変更するだけで親子コンポーネント間の通信が促進されます。プロパティが変更されると、デフォルトの実装によりコンポーネントが再レンダリングされます。\n\n### Destroy\n\nコンポーネントがDOMからアンマウントされると、Yewは`destroy`ライフサイクルメソッドを呼び出します。コンポーネントが破棄される前にクリーンアップ操作を実行する必要がある場合に便利です。このメソッドはオプションであり、デフォルトでは何も実行しません。\n\n### 無限ループ\n\nYewのライフサイクルメソッドでは無限ループが発生する可能性がありますが、それは各レンダリング後に同じコンポーネントを更新し、その更新が再レンダリングを要求する場合にのみ発生します。\n\n以下は簡単な例です：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // どのメッセージでも常に再レンダリングを要求します\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // レンダリングする内容は重要ではありません\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // この新しいメッセージを使用してコンポーネントを更新するように要求します\n        ctx.link().send_message(());\n    }\n}\n```\n\nここで何が起こっているのか見てみましょう：\n\n1. `create` 関数を使用してコンポーネントを作成します。\n2. `view` メソッドを呼び出して、Yew がブラウザの DOM にレンダリングする内容を知ることができます。\n3. `rendered` メソッドを呼び出し、`Context` リンクを使用して更新メッセージをスケジュールします。\n4. Yew がレンダリングフェーズを完了します。\n5. Yew はスケジュールされたイベントをチェックし、更新メッセージキューが空でないことを確認してメッセージを処理します。\n6. `update` メソッドを呼び出し、変更が発生し、コンポーネントが再レンダリングする必要があることを示す `true` を返します。\n7. ステップ2に戻ります。\n\n`rendered` メソッドで更新をスケジュールすることは依然として可能であり、これは通常便利ですが、その際にはこのループをどのように終了させるかを考慮してください。\n\n## 関連タイプ\n\n`Component` トレイトには、`Message` と `Properties` の2つの関連タイプがあります。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` タイプは、イベントが発生した後にコンポーネントにメッセージを送信するために使用されます。例えば、ユーザーがボタンをクリックしたり、ページをスクロールしたりしたときに何かを実行したい場合があります。コンポーネントは通常、複数のイベントに応答する必要があるため、`Message` タイプは通常、処理するイベントごとにバリアントを持つ列挙型です。\n\nコードベースを整理する際には、`Message` タイプの定義をコンポーネントを定義する同じモジュールに含めるのが賢明です。メッセージタイプの命名に一貫した命名規則を採用することが役立つ場合があります。一つのオプション（唯一のオプションではありませんが）は、タイプを `ComponentNameMsg` と命名することです。例えば、コンポーネントが `Homepage` と名付けられている場合、タイプを `HomepageMsg` と命名することができます。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` は、親コンポーネントからコンポーネントに渡される情報を表します。この型は `Properties` トレイトを実装する必要があり（通常はそれを派生させる）、特定のプロパティが必須かオプションかを指定できます。コンポーネントの作成および更新時にこの型が使用されます。コンポーネントのモジュール内で `Props` という名前の構造体を作成し、それをコンポーネントの `Properties` 型として使用するのが一般的な方法です。通常、\"properties\" は \"props\" と略されます。プロパティは親コンポーネントから渡されるため、アプリケーションのルートコンポーネントは通常、`Properties` 型として `()` を持ちます。ルートコンポーネントにプロパティを指定する場合は、`App::mount_with_props` メソッドを使用します。\n\n:::info\n[プロパティに関する詳細はこちら](./properties)\n:::\n\n## ライフサイクルコンテキスト\n\nすべてのコンポーネントライフサイクルメソッドは、コンテキストオブジェクトを受け取ります。このオブジェクトは、コンポーネントのスコープへの参照を提供し、コンポーネントにメッセージを送信したり、コンポーネントに渡されたプロパティを取得したりすることができます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Props)'\ndescription: '親子コンポーネント間の通信'\n---\n\nプロパティ (Properties) は、子コンポーネントと親コンポーネントの間で通信を可能にします。各コンポーネントには、親コンポーネントから渡される内容を記述するための関連プロパティ型があります。理論的には、これは `Properties` トレイトを実装した任意の型である可能性がありますが、実際には、各フィールドがプロパティを表す構造体であるべきです。\n\n## 派生マクロ\n\n`Properties` トレイトを自分で実装する必要はありません。`#[derive(Properties)]` を使用して実装を自動生成できます。`Properties` を派生する型は `PartialEq` も実装する必要があります。\n\n### フィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。以下の属性を使用すると、他の値が設定されていない限り、プロパティに初期値を提供できます。\n\n:::tip\nプロパティは Rustdoc によって生成されたドキュメントには表示されません。プロパティのドキュメント文字列には、そのプロパティがオプションであるかどうか、または特別なデフォルト値があるかどうかを記載する必要があります。\n:::\n\n#### `#[prop_or_default]`\n\nフィールド型のデフォルト値を使用してプロパティ値を初期化します。これは `Default` トレイトを使用します。\n\n#### `#[prop_or(value)]`\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。\n\n#### `#[prop_or_else(function)]`\n\n`function` を呼び出してプロパティ値を初期化します。`function` は `FnMut() -> T` のシグネチャを持つ必要があります。ここで、`T` はフィールド型です。\n\n## `PartialEq`\n\n`Properties` は `PartialEq` を実装する必要があります。これにより、Yew はそれらを比較し、変更があった場合に `changed` メソッドを呼び出すことができます。\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたポインタに基づいて格納されます。これにより、コンポーネントツリーに渡されるプロパティにはポインタのみが渡され、プロパティ全体をクローンすることによる高価なパフォーマンスオーバーヘッドを回避できます。\n\n:::tip\n`AttrValue` を使用してください。これは、クローンが必要な String やその他の類似の型を使用せずに済むようにするために提供されているカスタムプロパティ値型です。\n:::\n\n## 例\n\n```rust\nuse yew::Properties;\n/// virtual_dom から AttrValue をインポート\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// リンクにはターゲットが必要です\n    href: AttrValue,\n    /// また、String ではなく AttrValue を使用していることに注意してください\n    text: AttrValue,\n    /// リンクの色、デフォルトは `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 値が None の場合、ビュー関数はサイズを指定しません\n    #[prop_or_default]\n    size: Option<u32>,\n    /// ビュー関数がアクティブを指定しない場合、デフォルトは true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、属性や基本式 (`Foo { ..base }`) を使用することはできません。型パスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// リンクにはターゲットが必要です\n    href: AttrValue,\n    /// また、String ではなく AttrValue を使用していることに注意してください\n    text: AttrValue,\n    /// リンクの色、デフォルトは `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 値が None の場合、ビュー関数はサイズを指定しません\n    #[prop_or_default]\n    size: Option<u32>,\n    /// ビュー関数がアクティブを指定しない場合、デフォルトは true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// この関数は href と text を String として受け取ります\n    /// `AttrValue::from` を使用してそれらを `AttrValue` に変換できます\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '参照 (Refs)'\ndescription: 'DOM への越境アクセスを実現する'\n---\n\n`ref` キーワードは、任意の HTML 要素やコンポーネントに使用して、その要素に付随する DOM `Element` を取得できます。これにより、`view` ライフサイクルメソッドの外で DOM を変更することができます。\n\nこれは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。例えば、コンポーネントの `rendered` メソッドで `NodeRef` を使用すると、`view` からレンダリングされた後に canvas 要素に描画呼び出しを行うことができます。\n\n構文は次のとおりです：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 関連例\n\n- [ノード参照](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'スコープ'\ndescription: 'コンポーネントのスコープ'\n---\n\n## コンポーネントの `Scope<_>` インターフェース\n\n`Scope` は、メッセージを介してコールバックを作成し、自身を更新するメカニズムです。コンポーネントに渡されるコンテキストオブジェクトで `link()` を呼び出すことで、その参照を取得します。\n\n### `send_message`\n\nこの関数は、コンポーネントにメッセージを送信できます。メッセージは `update` メソッドによって処理され、コンポーネントが再レンダリングするかどうかを決定します。\n\n### `send_message_batch`\n\nこの関数は、コンポーネントに複数のメッセージを同時に送信できます。これは `send_message` に似ていますが、任意のメッセージが `update` メソッドで `true` を返す場合、バッチ内のすべてのメッセージの処理が完了した後にコンポーネントが再レンダリングされます。\n\n指定された引数ベクターが空の場合、この関数は何も実行しません。\n\n### `callback`\n\nコールバックを作成し、実行時にコンポーネントにメッセージを送信します。内部的には、提供されたクロージャが返すメッセージを使用して `send_message` を呼び出します。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // テキストを受け取り、それを `Msg::Text` メッセージバリアントとしてコンポーネントに送信するコールバックを作成します。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上の行は冗長であり、より明確にするために次のように簡略化できます：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // `Msg::Text(\"Hello World!\")` をコンポーネントに送信します。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // ここに HTML を配置\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nバッチメッセージを送信するコールバックを作成します。このメソッドに渡されるクロージャはメッセージを返す必要はありません。代わりに、クロージャは `Vec<Msg>` または `Option<Msg>` を返すことができます。ここで、`Msg` はコンポーネントのメッセージタイプです。\n\n`Vec<Msg>` はバッチメッセージとして扱われ、内部的に `send_message_batch` を使用します。\n\n`Option<Msg>` は値が `Some` の場合に `send_message` を呼び出します。値が `None` の場合は何も実行しません。これは、更新が不要な場合に使用できます。\n\nこれは、これらの型に対してのみ実装された `SendAsMessage` トレイトを使用して実現されています。独自の型に対して `SendAsMessage` を実装することで、`batch_callback` でそれらを使用できるようになります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/agents.mdx",
    "content": "---\ntitle: 'エージェント (Agents)'\ndescription: 'Yew のエージェントシステム'\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nエージェント (Agents) は、タスクを Web Workers にオフロードする方法です。\n\nエージェントが並行して動作できるようにするために、Yew は [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) を使用します。\n\n## ライフサイクル\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## エージェントの種類\n\n### 範囲\n\n- 公開 - 任意の時点で、公開エージェントのインスタンスは最大で1つだけです。ブリッジはWeb Worker内でエージェントを生成するか、既に生成されたエージェントに接続します。ブリッジがこのエージェントに接続されていない場合、エージェントは消滅します。\n\n- 私有 - 新しいブリッジごとにWeb Worker内で新しいエージェントを生成します。これは、ブラウザと通信する共有だが独立した動作をコンポーネントから移動するのに適しています。接続されたブリッジが破棄されると、エージェントは消滅します。\n\n- グローバル \\(WIP\\)\n\n## エージェントとコンポーネント間の通信\n\n### 通信ブリッジ (Bridges)\n\n通信ブリッジ（ブリッジ）は、コンポーネントとエージェント間の通信チャネルです。これにより、コンポーネントはエージェントにメッセージを送信し、エージェントからのメッセージを受信できます。\n\n`use_bridge` フックは、関数コンポーネント内でブリッジを作成する機能も提供します。\n\n### ディスパッチャー (Dispatchers)\n\nディスパッチャー（ディスパッチャー）は、コンポーネントとエージェント間の一方向通信を可能にし、コンポーネントがこの方法でエージェントにメッセージを送信します。\n\n## オーバーヘッド\n\nエージェントはWeb Workers（つまり、私有および公開）を使用します。メッセージの送受信時にシリアル化オーバーヘッドが発生します。エージェントは [bincode](https://github.com/bincode-org/bincode) を使用して他のスレッドと通信するため、コストは関数を呼び出すだけの場合よりもはるかに高くなります。\n\n## さらなる読み物\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) の例は、コンポーネントがエージェントにメッセージを送信し、エージェントからのメッセージを受信する方法を示しています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'classes! マクロを使用して CSS クラスを処理する'\ndescription: '便利なマクロを使用して CSS クラスを処理する'\ncomment: 'ファイルを短くシンプルに保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためであり、正確な API ドキュメントを提供するためではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew はネイティブの CSS-in-Rust ソリューションを提供していませんが、HTML の `class` 属性とプログラム的に対話する方法を提供することでスタイルを支援します。\n\n## `classes!` マクロ\n\n`classes!` マクロと関連する `Classes` 構造体は、HTML クラスの使用を簡素化します：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。\n\n## インラインスタイル\n\n現在、Yew は `style` 属性を使用して指定されたインラインスタイルを処理するための特別な支援ツールを提供していませんが、他の HTML 属性と同様に処理することができます：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'html! マクロを使用してHTMLを処理する'\ndescription: 'これはHTMLですが、完全にそうではありません！'\ncomment: 'ファイルを短く簡潔に保つようにしてください。これは、読者がYewのコンポーネントをより簡単に理解できるようにするためであり、正確なAPIドキュメントを提供するためではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロを使用して、HTML に似た式を記述できます。Yew はバックグラウンドでそれを DOM を表現する Rust コードに変換します。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nフォーマットされた式と同様に、波括弧を使用して周囲のコンテキストの値を HTML に埋め込むことができます：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n`html!` を使用する際の重要なルールの 1 つは、1 つのラッピングノードしか返せないということです。複数の要素のリストをレンダリングするために、`html!` は空のタグ（フラグメント）の使用を許可しています。空のタグは名前のないタグで、それ自体は HTML 要素を生成しません。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// エラー：ルート HTML 要素は1つだけ許可されています\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修正：HTML 空のタグを使用してラップする\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n詳細については、[HTML の詳細](concepts/html/introduction.mdx)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JavaScript と Rust'\ndescription: 'Rust で JavaScript を使用する'\ncomment: 'ファイルを簡潔に保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためのものであり、正確な API ドキュメントを提供するためのものではありません。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew は、再利用可能な UI 部分に必要なすべてのコンテンツを1か所に集める一方で、必要に応じて基盤技術へのアクセスも維持します。\n\n今日現在、WebAssembly は DOM との相互作用を完全にはサポートしていません。これは、Yew でも時々 JavaScript の呼び出しに依存することを意味します。次に、関係するライブラリの概要を示します。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しの橋を架けるライブラリとツールです。\n\n彼らの[ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/)と私たちの[クイックガイド](./wasm-bindgen.mdx)を強くお勧めします。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) は Web API のバインディングを提供し、Rust で処理され安全な方法で JavaScript コードを書くことを可能にします。\n\n例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n繰り返しになりますが、彼らの[ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/)と私たちの[クイックガイド](./web-sys.mdx)を強くお勧めします。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しブリッジを作成するためのライブラリおよびツールです。これは [Rust と WebAssembly ワーキンググループ](https://rustwasm.github.io/) によって Rust で構築されました。\n\nYew は `wasm-bindgen` を使用して、いくつかのクレートを介してブラウザと対話します：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nこのセクションでは、これらのクレートをより抽象的なレベルから探求し、Yew での `wasm-bindgen` API の理解と使用を容易にします。`wasm-bindgen` および関連するクレートに関する詳細なガイドについては、[`wasm-bindgen` ガイド](https://wasm-bindgen.github.io/wasm-bindgen/) を参照してください。\n\n上記のクレートのドキュメントについては、[`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) を参照してください。\n\n:::tip\n`wasm-bindgen` doc.rs 検索を使用して、`wasm-bindgen` を使用してインポートされたブラウザ API および JavaScript タイプを見つけます。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nこのクレートは、上記の他のクレートに多くの構成要素を提供します。このセクションでは、`wasm-bindgen` クレートの主要な領域の 2 つ、つまりマクロと、何度も目にするタイプ/トレイトのいくつかについてのみ説明します。\n\n### `#[wasm_bindgen]` マクロ\n\n`#[wasm_bindgen]` マクロは Rust と JavaScript の間のインターフェースを提供し、両者の間で変換を行うシステムを提供します。このマクロの使用はより高度であり、外部の JavaScript ライブラリを使用する場合を除いて使用しないでください。`js-sys` および `web-sys` クレートは、組み込みの JavaScript タイプおよびブラウザ API に対して `wasm-bindgen` 定義を提供します。\n\n`#[wasm-bindgen]` マクロを使用して、特定のバージョンの [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 関数をインポートする簡単な例を見てみましょう。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// まず、`web_sys` を使用せずに `console.log` を手動でバインドしてみましょう。\n// ここでは、手動で `#[wasm_bindgen]` アノテーションを書きます。プログラムの正確性はこれらのアノテーションの正確性に依存します！\n#[wasm_bindgen]\nextern \"C\" {\n    // ここで `js_namespace` を使用して `console.log(..)` をバインドします。`log(..)` だけではありません。\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` は多態的なので、複数のシグネチャを使用してバインドできます。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 複数の引数も可能です！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// インポートされた関数を使用します！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_この例は、[1.2 `wasm-bindgen` ガイドの console.log を使用する](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) に基づいています。_\n\n### 継承のシミュレーション\n\nJavaScript クラス間の継承は、JavaScript 言語のコア機能であり、DOM（ドキュメントオブジェクトモデル）はそれを中心に設計されています。`wasm-bindgen` を使用して型をインポートする際にも、それらの継承関係を記述する属性を追加できます。\n\nRust では、この継承関係は [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) と [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) トレイトを使用して表現されます。ここで例を挙げると役立つかもしれません。例えば、`A`、`B`、`C` という 3 つの型があり、`C` が `B` を拡張し、`B` が `A` を拡張しているとします。\n\nこれらの型をインポートする際、`#[wasm-bindgen]` マクロは次のように `Deref` と `AsRef` トレイトを実装します：\n\n- `C` は `B` に `Deref` できます\n- `B` は `A` に `Deref` できます\n- `C` は `B` に `AsRef` できます\n- `C` と `B` はどちらも `A` に `AsRef` できます\n\nこれらの実装により、`C` のインスタンスで `A` のメソッドを呼び出したり、`C` を `&B` または `&A` として使用したりできます。\n\n注意すべき点は、`#[wasm-bindgen]` を使用してインポートされたすべての型には同じルート型があり、それを上記の例の `A` と見なすことができるということです。この型は [`JsValue`](#jsvalue) であり、以下にそのセクションがあります。\n\n_[`wasm-bindgen` ガイドの extends セクション](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\nこれは JavaScript が所有するオブジェクトの表現であり、`wasm-bindgen` のルートキャプチャ型です。`wasm-bindgen` からの任意の型は `JsValue` です。これは、JavaScript には強い型システムがないため、変数 `x` を受け取る任意の関数がその型を定義しないため、`x` は有効な JavaScript 値である可能性があるためです。したがって `JsValue` です。`JsValue` を受け取るインポート関数や型を使用している場合、技術的には任意のインポート値が有効です。\n\n`JsValue` は関数で受け取ることができますが、その関数は特定の型のみを受け取る可能性があり、それがパニックを引き起こす可能性があります。したがって、元の `wasm-bindgen` API を使用する場合は、インポートされた JavaScript のドキュメントを確認して、その値が特定の型でない場合に例外（パニック）を引き起こすかどうかを確認してください。\n\n_[`JsValue` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)_\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust には強い型システムがありますが、JavaScript にはありません😞。Rust がこれらの強い型を維持しながらも便利であるために、WebAssembly ワーキンググループは非常に巧妙な機能 `JsCast` を提案しました。これは、ある JavaScript \"型\" から別の \"型\" への変換を支援するものです。これは曖昧に聞こえますが、ある型が別の型であることがわかっている場合、`JsCast` の関数を使用してある型から別の型にジャンプできます。`web-sys`、`wasm_bindgen`、`js-sys` を使用する際にこの機能を理解しておくと便利です。これらのクレートから多くの型が `JsCast` を実装していることに気付くでしょう。\n\n`JsCast` はチェック付きとチェックなしの変換メソッドを提供します。したがって、実行時にオブジェクトがどの型であるかわからない場合は、変換を試みることができ、失敗する可能性のある型として [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) や [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) を返します。\n\n一般的な例は [`web-sys`](./web-sys.mdx) で、イベントのターゲットを取得しようとする場合です。ターゲット要素が何であるかを知っているかもしれませんが、[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API は常に [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を返します。\nその要素型に変換する必要があり、そのメソッドを呼び出すことができます。\n\n```rust\n// このトレイトを最初にインポートする必要があります\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // もしかしたらターゲットは選択要素かもしれませんか？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 別のことをする\n        return;\n    }\n\n    // それが選択要素でないことが確実であれば、入力要素であることが確実です！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) メソッドはチェック付きの変換であり、`Option<&T>` を返します。これは、変換が失敗した場合に元の型を再度使用できることを意味し、`None` を返します。 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) メソッドは `self` を消費し、Rust の `into` メソッドの規約に従い、`Result<T, Self>` 型を返します。変換が失敗した場合、元の `Self` 値は `Err` に返されます。再試行するか、元の型で他の操作を行うことができます。\n\n_[`JsCast` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 型は、Rust のクロージャを JavaScript に渡す方法を提供します。健全性の理由から、JavaScript に渡されるクロージャは `'static` ライフタイムを持つ必要があります。\n\nこの型は「ハンドル」であり、破棄されると、それが参照する JS クロージャを無効にします。`Closure` が破棄された後、JS 内のクロージャの使用はすべて例外を引き起こします。\n\n`Closure` は、[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 型を受け取る `js-sys` または `web-sys` API を使用する際に一般的に使用されます。Yew で `Closure` を使用する例は、[Events](../html/events.mdx) ページの[Using `Closure` セクション](../html/events.mdx#using-closure-verbose) にあります。\n\n_[`Closure` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` クレートは、JavaScript の標準組み込みオブジェクトのバインディング/インポートを提供します。これには、それらのメソッドやプロパティが含まれます。\n\nこれは Web API を含みません。Web API は [`web-sys`](./web-sys.mdx) の役割です！\n\n_[`js-sys` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` クレートは、JavaScript の Promise 型を Rust の [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) として扱うためのブリッジを提供し、Rust の Future を JavaScript の Promise に変換するユーティリティを含みます。Rust（wasm）で非同期または他のブロッキング作業を処理する際に役立ち、JavaScript のイベントや JavaScript I/O プリミティブと対話する能力を提供します。\n\n現在、このクレートには3つの主要なインターフェースがあります：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) を使用して構築された型で、`Future<Output=Result<JsValue, JsValue>>` として使用できます。`Promise` が解決されると、この `Future` は `Ok` に解決され、`Promise` が拒否されると `Err` に解決され、それぞれ `Promise` の解決または拒否の値を含みます。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Rust の `Future<Output=Result<JsValue, JsValue>>` を JavaScript の `Promise` に変換します。Future の結果は、JavaScript 内の解決または拒否された `Promise` に変換されます。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   現在のスレッドで `Future<Output = ()>` を生成します。これは、Rust 内で Future を実行する最良の方法であり、JavaScript に送信するのではなく、Rust 内で実行します。\n\n_[`wasm-bindgen-futures` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` は、非同期 API を使用するライブラリを使用する際に、Yew で `wasm-bindgen-futures` クレートの最も一般的に使用される部分です。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // \"Hello, world!\" を出力します\n    console::log_1(&string.into());\n});\n```\n\nYew はいくつかの API に futures のサポートを追加しており、特に `async` ブロックを受け入れる `callback_future` を作成できることが注目されます。これは内部的に `spawn_local` を使用しています。\n\n_[`spawn_local` ドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys クレートは Web API のバインディングを提供します。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` クレート](https://crates.io/crates/web-sys) は Web API のバインディングを提供します。これはブラウザの WebIDL から生成されるため、名前が長くなったり、型が曖昧になったりすることがあります。\n\n## `web-sys` の特性 (features)\n\n`web-sys` クレートで全ての特性を有効にすると、Wasm アプリケーションに多くの冗長性が追加される可能性があります。この問題を解決するために、ほとんどの型は特性を有効にすることで制御され、アプリケーションに必要な型だけを含めることができます。Yew は `web-sys` のいくつかの特性を有効にし、その公開 API でいくつかの型を公開しています。通常、`web-sys` を依存関係として追加する必要があります。\n\n## `web-sys` の継承\n\n[継承のシミュレーション](./wasm-bindgen.mdx#simulating-inheritance)のセクションでは、Rust が通常 JavaScript の継承をシミュレートする方法を提供していることがわかります。これは `web-sys` で非常に重要です。ある型にどのようなメソッドがあるかを理解するためには、その継承を理解する必要があります。\n\nこのセクションでは、特定の要素を見て、Rust で [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) を呼び出して、その値が [`JsValue`](./wasm-bindgen.mdx#jsvalue) になるまでの継承をリストします。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement は HTML の <textarea> です。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意: ここで web-sys タイプから js-sys クレート内の組み込み JavaScript タイプに移行しました。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意: ここで js-sys タイプから wasm-bindgen クレートのルート JsValue に移行しました。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // このように deref を使用することで、継承ツリーを手動でたどる必要があります。\n    // しかし、HtmlTextAreaElement タイプで JsValue メソッドを呼び出すことができます。\n    assert!(!text_area.is_string());\n\n    // この空の関数は、HtmlTextAreaElement を &EventTarget として渡すことができることを示すためのものです。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // コンパイラはここでタイプを一致させるために deref チェーンを下にたどります。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 実装により、HtmlTextAreaElement を &EventTarget として扱うことができます。\n    let event_target: &EventTarget = text_area.as_ref();\n}\n```\n\n[`wasm-bindgen` ガイドの `web-sys` 継承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)\n\n## `NodeRef` の `Node`\n\nYew は [`NodeRef`](concepts/function-components/node-refs.mdx) を使用して、[`html!`](concepts/html/introduction.mdx) マクロによって作成された `Node` の参照を保持する方法を提供します。`NodeRef` の `Node` は [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html) を指します。`NodeRef::get` メソッドは `Option<Node>` 値を返しますが、Yew ではほとんどの場合、この値を特定の要素に変換して、その特定のメソッドを使用することを望みます。存在する場合、[`JsCast`](./wasm-bindgen.mdx#JsCast) を使用して `Node` 値を変換できますが、Yew はこの変換を実行するための `NodeRef::cast` メソッドを提供しているため、`JsCast` 特性のために `wasm-bindgen` 依存関係を含める必要はありません。\n\n以下の2つのコードブロックは本質的に同じです。最初のものは `NodeRef::cast` を使用し、2 番目のものは `NodeRef::get` が返す `web_sys::Node` 上で [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) を使用しています。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // HtmlInputElement をここで処理します\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // HtmlInputElement をここで処理します\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Rust にリファクタリングされた JavaScript の例\n\nこのセクションでは、Web API と対話する JavaScript コードの例を Rust の `web-sys` にリファクタリングする方法を示します。\n\n### JavaScript の例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e はマウスイベントオブジェクトです\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 要素内の x 位置。\n    var y = e.clientY - rect.top // 要素内の y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` を使用して書き直した例\n\n`web-sys` のみを使用して、上記の JavaScript の例は次のように実装できます：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 使用したいすべての web-sys 機能を有効にする必要があります！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 現在、イベントが発生したときにクロージャがメモリに残るように、`mousemove` クロージャを保存する必要があります。\n```\n\nこのバージョンはより冗長ですが、その一部は失敗した型が私たちにいくつかの関数呼び出しに保持しなければならない不変条件を思い出させるためです。これらの不変条件が守られないと、Rust ではパニックが発生します。もう一つの冗長な部分は、特定のメソッドを呼び出すために異なる型を特定の型に変換するための `JsCast` の呼び出しです。\n\n### Yew で書き直した例\n\nYew では、主に [`Callback`](concepts/function-components/callbacks.mdx) を作成して [`html!`](concepts/html/introduction.mdx) マクロで使用するため、例はこの方法を使用します。上記の方法を完全にコピーするのではなく、この方法を使用します：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# `get_bounding_client_rect` メソッドを使用するには、`DomRect` 特性を有効にする必要があります。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 追加の依存ライブラリ\n\n`web-sys` は Web API の生のバインディングであるため、Rust で使用する際にはいくつかの困難が伴います。これは、`web-sys` が Rust や強い型システムのために設計されていないためです。そこで、コミュニティのクレートが `web-sys` に対する抽象化を提供し、Rust の慣習により適した API を提供しています。\n\n_[追加の依存ライブラリ一覧](/community/external-libs)_\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/contexts.mdx",
    "content": "---\ntitle: 'コンテキスト (Contexts)'\nsidebar_label: コンテキスト\ndescription: 'コンテキストを使用して深くネストされたデータを渡す'\n---\n\n通常、データは props を介して親コンポーネントから子コンポーネントに渡されます。\nしかし、多くの中間コンポーネントを介してデータを渡す必要がある場合や、アプリケーション内の多くのコンポーネントが同じ情報を必要とする場合、props を介してデータを渡すことは冗長で煩わしいものになります。\nコンテキストはこの問題を解決し、親コンポーネントがデータをその下のツリー内の任意のコンポーネントに渡すことを可能にし、props を介してデータを渡す必要がなくなります。\n\n## Props を使用する際の問題：\"Prop Drilling\"\n\n[props](./function-components/properties.mdx) を介してデータを親コンポーネントから直接子コンポーネントに渡すことは良い方法です。\nしかし、深くネストされたコンポーネントツリーを介してデータを渡す必要がある場合や、複数のコンポーネントが同じデータを共有する必要がある場合、props を渡すことは煩雑になります。\n一般的なデータ共有の解決策は、データを共通の祖先に持ち上げ、子コンポーネントがそれを props として受け取るようにすることです。\nしかし、これにより props が複数のコンポーネントを介して渡される必要がある場合があります。\nこの状況は \"Prop Drilling\" と呼ばれます。\n\n以下の例を考えてみましょう。これは props を介してテーマを渡しています：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// アプリのルート\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n私たちはテーマ設定を `Navbar` に渡して、それが `Title` と `NavButton` に到達するようにしています。\nもし `Title` と `NavButton` のようなテーマにアクセスする必要があるコンポーネントが、prop を介さずに直接テーマにアクセスできるとしたら、もっと良いでしょう。\nコンテキストはこの問題を解決し、親コンポーネントがデータ（この場合はテーマ）をその子コンポーネントに渡すことを可能にします。\n\n## コンテキストの使用\n\n### ステップ 1：コンテキストの提供\n\nコンテキストを消費するには、コンテキストプロバイダーが必要です。`ContextProvider<T>` は、`T` がコンテキスト構造体として使用されるプロバイダーです。\n`T` は `Clone` と `PartialEq` を実装する必要があります。`ContextProvider` は、その子コンポーネントがコンテキストを持つコンポーネントです。\nコンテキストが変更されると、子コンポーネントは再レンダリングされます。データを渡すための構造体が定義されます。`ContextProvider` は次のように使用できます：\n\n```rust\nuse yew::prelude::*;\n/// アプリのテーマ\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// メインコンポーネント\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` は `Rc<UseStateHandle<Theme>>` 型であり、`Theme` が必要です\n        // したがって、デリファレンスします。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // ここにあるすべての子コンポーネントとその子コンポーネントは、このコンテキストにアクセスします。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// ツールバー\n/// このコンポーネントはコンテキストにアクセスできます。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// `Toolbar` 内に配置されたボタン\n/// このコンポーネントは、コンポーネントツリー内の `ThemeContextProvider` の子コンポーネントであるため、\n/// コンテキストにアクセスできます。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### ステップ 2：コンテキストの使用\n\n#### 関数コンポーネント\n\n`use_context` フックは、関数コンポーネント内でコンテキストを使用するために使用されます。\n詳細については、[use_context ドキュメント](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) を参照してください。\n\n#### 構造体コンポーネント\n\n構造体コンポーネント内でコンテキストを使用するには、2つの方法があります：\n\n- [高階コンポーネント](../advanced-topics/struct-components/hoc)：高階関数コンポーネントがコンテキストを使用し、必要なデータを構造体コンポーネントに渡します。\n- 構造体コンポーネント内で直接コンテキストを使用します。詳細については、[構造体コンポーネントのコンシューマーとしての例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs) を参照してください。\n\n## 使用シナリオ\n\n通常、ツリーの異なる部分のリモートコンポーネントでデータを使用する必要がある場合、コンテキストが役立ちます。\n以下はいくつかの例です：\n\n- **テーマ**：アプリケーションのトップにコンテキストを配置し、アプリケーションのテーマを保持し、視覚的な外観を調整するために使用できます（上記の例を参照）。\n- **現在のユーザーアカウント**：多くの場合、コンポーネントは現在ログインしているユーザーを知る必要があります。コンテキストを使用して、現在のユーザーオブジェクトをコンポーネントに提供できます。\n\n### コンテキストを使用する前の考慮事項\n\nコンテキストは非常に使いやすいですが、それが誤用/過度に使用される可能性もあります。\n複数のレベル深いコンポーネントに props を共有するためにコンテキストを使用できるからといって、必ずしもそうすべきではありません。\n\n例えば、コンポーネントを抽出して、そのコンポーネントを別のコンポーネントの子コンポーネントとして渡すことができます。\n例えば、`Layout` コンポーネントが `articles` を prop として受け取り、それを `ArticleList` コンポーネントに渡す場合、\n`Layout` コンポーネントをリファクタリングして、子コンポーネントを props として受け取り、`<Layout> <ArticleList {articles} /> </Layout>` と表示するようにするべきです。\n\n## 子コンポーネントのコンテキスト値を変更する\n\nRust の所有権ルールにより、コンテキストには子コンポーネントが呼び出せる `&mut self` メソッドを持つことができません。\nコンテキストの値を変更するには、リデューサーと組み合わせて使用する必要があります。これは、[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) フックを使用して行うことができます。\n\n[コンテキストの例](https://github.com/yewstack/yew/tree/master/examples/contexts) は、可変コンテキストの使用を示しています。\n\n## さらなる読み物\n\n- [コンテキストの例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'コールバック (Callbacks)'\n---\n\nコールバック関数は、コンポーネントツリー内で情報を上向きに伝達したり、イベント処理中に他のコンポーネント（例えばエージェントやDOM）と通信したりするために使用されます。内部的には、コールバック関数の型は単なる `Fn` であり、安価にクローンできるように `Rc` に包まれています。\n\nコールバック関数を手動で呼び出したい場合は、`emit` 関数を使用できます。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // コールバック関数を呼び出す\n// web_sys::console::log_1(&result.into()); // コメントを解除すると、「Bye Bob」 が出力されます\n```\n\n## コールバック関数をプロパティとして渡す\n\nyew で一般的なパターンは、コールバック関数を作成し、それをプロパティとして子コンポーネントに渡すことです。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 次にプロパティ (Props) を提供します\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // コメントを解除すると、ここにテキストが出力されます\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM イベントとコールバック関数\n\nコールバック関数は、DOM イベントに接続するためにも使用されます。\n\n例えば、ここではユーザーがボタンをクリックしたときに呼び出されるコールバック関数を定義します：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // コメントを解除すると、ここにテキストが出力されます\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子要素 (Children)'\n---\n\n`Children` は特別なプロパティタイプで、HTMLの子要素のようにネストされた `Html` を受け取ることができます。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` キーは重要です！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // この方法で子要素を転送できます\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'コンポーネント間の通信'\n---\n\n## 親コンポーネントから子コンポーネントへのメッセージ送信\n\nデータを [props](./properties) として渡すと、再レンダリングが発生し、これが子コンポーネントにメッセージを渡す方法です。\n\n## 子コンポーネントから親コンポーネントへのメッセージ送信\n\nprops を介してコールバックを渡し、子コンポーネントはイベントでそれを呼び出すことができます。[例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'ジェネリックコンポーネント'\ndescription: '関数コンポーネントの #[component] 属性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 属性は、ジェネリックコンポーネントを作成するためのジェネリック関数にも適用されます。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// その後、このように使用できます\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// または\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'カスタムフック'\n---\n\n## カスタムフックの定義\n\nコンポーネントのステートフルなロジックは、カスタムフックを作成することで再利用可能な関数として抽出できます。\n\n例えば、`window` オブジェクト上のイベントをリッスンするイベントリスナーを作成したいとします。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nこのコードには問題があります。ロジックは他のコンポーネントで再利用できません。異なるイベントをリッスンする別のコンポーネントを作成する場合、コードをコピーするのではなく、ロジックをカスタムフックに移すことができます。\n\nまず、`use_event` という新しい関数を作成します。`use_` プレフィックスは関数がフックであることを示します。この関数はイベントターゲット、イベントタイプ、およびコールバックを受け取ります。すべてのフックはその関数定義に `#[hook]` とマークする必要があります。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nこのシンプルなフックは、組み込みのフックを組み合わせることで作成できます。この例では、`use_effect_with` フックを使用します。これにより、フックのパラメータが変更されたときにイベントリスナーを再作成できます。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nこの方法はほとんどすべてのケースで有効ですが、私たちがすでに使用しているような基本的なフックを作成するためには使用できません。\n\n[docs.rs](https://docs.rs/yew) 上のドキュメントや `hooks` ディレクトリを参照して、事前定義されたフックの実装を確認してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks は、状態を保存し、副作用を実行することができる関数の一種です。\n\nYew はいくつかの事前定義された hooks を提供しています。また、自分で hooks を作成することもできますし、多くの[コミュニティ製の hooks](/community/awesome#hooks) を見つけることもできます。\n\n## Hooks のルール\n\n1. 各 Hook 関数の名前は `use_` で始める必要があります\n2. Hooks は次の場所でのみ使用できます：\n    - 関数/ Hook のトップレベル\n    - 関数/ Hook 内のブロック、ただし分岐していない場合\n    - 関数/ Hook 内トップレベルの `if` 式の条件\n    - 関数/ Hook 内トップレベルの `match` 式のセレクター\n3. 各レンダリング時に、Hooks は同じ順序で呼び出される必要があります。[Suspense](../../suspense.mdx) を使用する場合のみ、早期リターンが許可されます\n\nこれらのルールは、コンパイル時または実行時のエラーによって強制されます。\n\n### 事前定義された Hooks\n\nYew は次の事前定義された Hooks を提供しています：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nこれらの hooks のドキュメントは [Yew API ドキュメント](https://yew-rs-api.web.app/next/yew/functional/)で見つけることができます。\n\n### カスタム Hooks\n\n場合によっては、独自の Hooks を定義して、コンポーネント内の状態を持つ可能性のあるロジックを再利用可能な関数にカプセル化することが望ましいことがあります。\n\n## さらなる読み物\n\n- React ドキュメントには [React hooks](https://reactjs.org/docs/hooks-intro.html) に関するセクションがあります。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '関数コンポーネント'\nslug: /concepts/function-components\n---\n\n以前のスローガンをもう一度見てみましょう：\n\n> Yew の核心思想は、再利用可能な UI 部分に必要なすべての内容を 1 つの場所 - Rust ファイルに集中させることです。\n\nこの声明を完成させるために、アプリケーションのロジックとレンダリングの動作を定義する概念を導入します：\"コンポーネント\"。\n\n## コンポーネントとは？\n\nコンポーネントは Yew の構成要素です。\n\nそれらは次のことを行うべきです：\n\n- [Props](./properties.mdx) の形式でパラメータを受け取る\n- 独自の状態を持つことができる\n- ユーザーに見える HTML フラグメント（DOM）を計算する\n\n## Yew コンポーネントの 2 つのフレーバー\n\n現在、関数コンポーネントについて読んでいます - これは Yew を使い始めるときや、シンプルなレンダリングロジックを書くときにコンポーネントを書くための推奨方法です。\n\nもう一つの、より高度ですがアクセスしにくいコンポーネントの書き方があります - [構造コンポーネント](advanced-topics/struct-components/introduction.mdx)。それらは非常に詳細な制御を可能にしますが、ほとんどの場合、そこまで詳細な制御は必要ありません。\n\n## 関数コンポーネントの作成\n\n関数コンポーネントを作成するには、関数に `#[component]` 属性を追加します。慣例として、関数の名前は PascalCase を使用し、`html!` マクロ内の通常の html 要素と対比させます。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// そして他の場所で、`html!` 内でコンポーネントを使用できます\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## コンポーネント内部で何が起こっているのか\n\nレンダリング時に、Yew はこれらのコンポーネントの仮想ツリーを構築します。各（関数）コンポーネントの view 関数を呼び出して、DOM の仮想バージョン（VDOM）を計算します。ライブラリのユーザーとして、これを `Html` 型として扱います。上記の例では、次のようになります：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n更新が必要な場合、Yew は再び view 関数を呼び出し、新しい仮想 DOM を以前のバージョンと調整し、新しい/変更された/必要な部分のみを実際の DOM に伝播します。これが **レンダリング** と呼ばれるものです。\n\n:::note\n\n実際には、`Html` は `VNode` の別名に過ぎません - 仮想ノードです。\n\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'ノード参照'\ndescription: 'DOM 外部アクセス'\n---\n\n`ref` 属性を使用して、`NodeRef` を HTML 要素にアタッチできます。コールバック内で、`ref` がアタッチされた DOM `Element` を取得できます。これを使用して、`view` ライフサイクルメソッドの外部で DOM を変更したり、`<input>` の値を取得したり、JavaScript API を介して直接 DOM と対話したりできます。\n\nこれは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。\n\n:::caution\nYew がレンダリングした DOM ツリーを手動で変更しないでください。確信が持てない場合は、`NodeRef` を読み取り専用アクセスとして扱ってください。\n:::\n\n## さらに読む\n\n- [use_node_ref フック](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` の例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'プロパティ (Properties)'\ndescription: '親子コンポーネントの通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nプロパティ (Properties) は通常 \"Props\" と略されます。\n\n:::\n\nプロパティ (Properties) はコンポーネントのパラメータであり、Yew はこれらのパラメータを監視できます。\n\nコンポーネントのプロパティで型を使用する前に、その型は `Properties` トレイトを実装している必要があります。\n\n## リアクティブ性\n\n再レンダリング時に、Yew は仮想DOMを調整する際にプロパティが変更されたかどうかを確認し、ネストされたコンポーネントを再レンダリングする必要があるかどうかを判断します。これにより、Yew は非常にリアクティブなフレームワークと見なされます。親コンポーネントからの変更は常に下位に伝播し、ビューはプロパティ/状態からのデータと常に同期します。\n\n:::tip\n\nまだ [チュートリアル](../../tutorial) を完了していない場合は、このリアクティブ性を自分でテストしてみてください！\n\n:::\n\n## 派生マクロ\n\nYew は、構造体に `Properties` トレイトを簡単に実装できる派生マクロを提供します。\n\n`Properties` を派生する型は、Yew がデータ比較を行えるように `PartialEq` も実装している必要があります。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 関数コンポーネントでの使用\n\n属性 `#[component]` は、関数の引数で Props を選択的に受け取ることを可能にします。それらを提供するには、`html!` マクロ内の属性を通じて割り当てることができます。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// そしてプロパティを提供します\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 提供するプロパティはありません\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生マクロフィールド属性\n\n`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。\n\n以下の属性を使用すると、親コンポーネントがそれらを設定しなかった場合にデフォルト値を提供することができます。\n\n:::tip\n属性は Rustdoc によって生成されたドキュメントには表示されません。属性のドキュメント文字列には、その属性がオプションであるかどうか、および特定のデフォルト値があるかどうかを記載する必要があります。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n`Default` トレイトを使用して、フィールド型のデフォルト値でプロパティ値を初期化します。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。\n\n例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。プロパティが構築されるときに、式が評価され、明示的な値が与えられていない場合に適用されます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n属性値を初期化するために `function` を呼び出します。`function` は `FnMut() -> T` シグネチャを持つ必要があり、ここで `T` はフィールドの型です。このプロパティに明示的な値が与えられていない場合、その関数が呼び出されます。\nこの関数はプロパティが構築されるときに呼び出されます。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// デフォルト値を使用する\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// またはデフォルト値を上書きしない\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Properties のパフォーマンスオーバーヘッド\n\n内部プロパティは参照カウントされたスマートポインタとして渡されます。これにより、コンポーネントツリー内のプロパティに対して共有ポインタが1つだけ渡されるため、プロパティ全体をクローンする高コストを節約できます。\n\n:::tip\n`AttrValue` はプロパティ値に使用するカスタムタイプであり、これにより String やその他のクローンコストが高いタイプとして定義する必要がなくなります。\n:::\n\n## Props マクロ\n\n`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。\n\nこのマクロは構造体の式と同じ構文を使用しますが、プロパティや基本式 (`Foo { ..base }`) を使用することはできません。タイプパスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`MyComp::Properties`) に指すこともできます。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 名前属性を指定する必要はありません\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自動生成プロパティ (yew-autoprops)\n\n開発プロセスを簡素化するために、`#[autoprops]` マクロ（`yew-autoprops` パッケージから）を使用して `Properties` 構造体を自動生成することもできます。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] マクロは #[component] の前に配置する必要があります。順序が重要です。\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 構造体 \"GreetingsProps\" は自動的に生成されます。\n//\n// `is_loading` は値としてコンポーネントに渡され、`message` と `name` は定義に先行する `&` があるため参照として渡されます。\n```\n\n## 評価順序\n\n属性は指定された順序で評価されます。以下の例を参照してください：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## アンチパターン\n\nほとんどのRust型はプロパティとして渡すことができますが、避けるべきアンチパターンがいくつかあります。これらには以下が含まれますが、これに限定されません：\n\n1. `String` 型を `AttrValue` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `String` のクローンは高コストです。プロパティ値がフックやコールバックと一緒に使用される場合、通常クローンが必要です。`AttrValue` は参照カウントされた文字列 (`Rc<str>`) または `&'static str` であり、非常に安価にクローンできます。<br />\n   **注意**：`AttrValue` は内部的には [implicit-clone](https://crates.io/crates/implicit-clone) からの `IString` です。詳細はそのパッケージを参照してください。\n2. 内部可変性を使用する。 <br />\n   **なぜ悪いのか？** 内部可変性（例えば `RefCell`、`Mutex` など）は _通常_ 避けるべきです。これにより再レンダリングの問題が発生する可能性があり（Yewは状態が変更されたことを認識しません）、手動で再レンダリングを強制する必要があるかもしれません。すべてのものと同様に、適切な使用場所があります。慎重に使用してください。\n3. `Vec<T>` 型を `IArray<T>` の代わりに使用する。 <br />\n   **なぜ悪いのか？** `Vec<T>` も `String` と同様にクローンのコストが高いです。`IArray<T>` は参照カウントされたスライス (`Rc<[T]>`) または `&'static [T]` であり、非常に安価にクローンできます。<br />\n   **注意**：`IArray` は [implicit-clone](https://crates.io/crates/implicit-clone) からインポートできます。詳細はそのパッケージを参照してください。\n4. 新しい発見があるかもしれません。早く知っておきたかったエッジケースに遭遇しましたか？問題を作成するか、このドキュメントに修正のPRを提供してください。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) は実験的なパッケージで、関数の引数に基づいて動的にProps構造体を作成することを可能にします。プロパティ構造体が再利用されない場合、これは有用かもしれません。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '純粋コンポーネント'\n---\n\nすべての関数コンポーネントは、プロパティオブジェクトを受け取り、`Html` オブジェクトを返す[純粋](https://ja.wikipedia.org/wiki/%E7%B4%94%E9%96%A2%E6%95%B0)関数です。純粋関数とは、同じ入力に対して常に同じ出力を返す関数のことです。\n\nこの例は純粋コンポーネントです。与えられたプロパティ `is_loading` に対して、常に同じ `Html` を返し、副作用はありません。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n内部の純粋コンポーネントがフックや他のコンポーネントメカニズムを使用しない場合、それを `Html` を返す通常の関数として記述することができ、Yew がコンポーネントのライフサイクルに関連するオーバーヘッドを回避することができます。[式構文](concepts/html/literals-and-expressions.mdx#expressions) を使用して `html!` 内でそれらをレンダリングします。\n:::\n\n## 非純粋コンポーネント\n\nコンポーネントがグローバル変数を使用しない場合、それが「純粋」でない可能性があるかどうか疑問に思うかもしれません。なぜなら、それは毎回レンダリングされる固定関数として呼び出されるだけだからです。\nこれが次のトピック - [フック](./hooks) の出番です。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/state.mdx",
    "content": "---\ntitle: '状態'\n---\n\n## 状態を保存するための一般的なビュー\n\nこの表は、どの状態保存タイプがあなたのユースケースに最適かを決定するためのガイドとして役立ちます：\n\n| フック             | タイプ                     | いつレンダリングされるか                   | スコープ                     |\n| ------------------ | -------------------------- | ------------------------------------------ | ---------------------------- |\n| [use_state]        | `T`                        | 値が設定されたとき                         | コンポーネントインスタンス内 |\n| [use_state_eq]     | `T: PartialEq`             | 異なる値が設定されたとき                   | コンポーネントインスタンス内 |\n| [use_reducer]      | `T: Reducible`             | リデューサーが呼び出されたとき             | コンポーネントインスタンス内 |\n| [use_reducer_eq]   | `T: Reducible + PartialEq` | リデューサーが呼び出され、結果が異なるとき | コンポーネントインスタンス内 |\n| [use_memo]         | `Deps -> T`                | 依存関係が変わったとき                     | コンポーネントインスタンス内 |\n| [use_callback]     | `Deps -> Callback<E>`      | 依存関係が変わったとき                     | コンポーネントインスタンス内 |\n| [use_mut_ref]      | `T`                        | -                                          | コンポーネントインスタンス内 |\n| グローバル静的定数 | `T`                        | -                                          | グローバル、どこでも使用可能 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/classes.mdx",
    "content": "---\ntitle: 'クラス'\ndescription: 'クラスを処理するための便利なマクロ'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## クラス\n\n`Classes` 構造体は、HTML クラスを処理するために使用できます。\n\n文字列をコレクションにプッシュすると、`Classes` は各クラスが一つの要素を持つことを保証します。単一の文字列が複数のクラスを含む場合でも同様です。\n\n`Classes` は、`Extend`（例：`classes1.extend(classes2)`）や `push()`（例：`classes1.push(classes2)`）を使用してマージすることもできます。`Into<Classes>` を実装している任意の型を既存の `Classes` にプッシュすることができます。\n\n`classes!` は、単一の `Classes` を作成するための便利なマクロです。その入力はカンマで区切られた式のリストを受け入れます。唯一の要件は、各式が `Into<Classes>` を実装していることです。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## クラスを受け入れるコンポーネント\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/components.mdx",
    "content": "---\ntitle: 'コンポーネント'\ndescription: 'コンポーネント階層を使用して複雑なレイアウトを作成する'\n---\n\n## 基本\n\nコンポーネントは `html!` マクロで使用できます：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // プロパティなし\n        <MyComponent />\n\n        // プロパティを使用\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // すべてのプロパティを一度に提供\n        <MyComponentWithProps ..props.clone() />\n\n        // 変数のプロパティを使用し、特定の値を上書き\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## ネスト\n\nコンポーネントの `Properties` に `children` フィールドがある場合、子コンポーネント/要素を受け入れることができます。\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` マクロは、各プロパティを個別に指定するのではなく、基本式を `..props` 構文で渡すことを可能にします。これは Rust の[関数的更新構文](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax)に似ています。\nこの基本式は、個別のプロパティを渡した後に現れる必要があります。\n`children` フィールドを持つ基本 props 式を渡す場合、`html!` マクロ内で渡された子要素は、props 内に既に存在する子要素を上書きします。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子要素は props.children を上書きします\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 参考例\n\n- [関数型 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [関数型ルーティング](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '条件レンダリング'\ndescription: 'HTMLで条件付きノードをレンダリングする！'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If ブロック\n\n条件付きでマークアップをレンダリングするには、それを `if` ブロックでラップします：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/elements.mdx",
    "content": "---\ntitle: '要素'\ndescription: 'HTML および SVG 要素のサポート'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM ノード\n\nYew で DOM ノードを手動で作成または管理する理由はたくさんあります。たとえば、管理されたコンポーネントと競合する可能性のある JS ライブラリとの統合などです。\n\n`web-sys` を使用すると、DOM 要素を作成して `Node` に変換できます。次に、`VRef` を使用して `Html` 値として使用できます：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // メモ化された関数、一度だけ実行されます\n    let node = use_memo(\n        (),\n        |_| {\n            // ドキュメントから div 要素を作成\n            let div: Element = document().create_element(\"div\").unwrap();\n            // コンテンツ、クラスなどを追加\n            div.set_inner_html(\"Hello, World!\");\n            // Element を Node に変換\n            let node: Node = div.into();\n            // その Node を Html 値として返す\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo は Rc ポインタを返すので、参照解除とクローンが必要です\n    (*node).clone()\n}\n\n```\n\n## 動的なタグ名\n\n高階コンポーネントを構築する際、タグ名が静的ではない状況に遭遇することがあります。例えば、`Title` コンポーネントがあり、レベル属性に応じて `h1` から `h6` までの任意の内容をレンダリングする場合です。大きなマッチ式を使用する代わりに、Yew は `@{name}` を使用してタグ名を動的に設定することを許可します。ここで、`name` は文字列を返す任意の式です。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 論理値属性\n\nいくつかのコンテンツ属性（例えば、checked、hidden、required）は論理値属性と呼ばれます。Yew では、論理値属性はブール値に設定する必要があります：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nこれは次の **HTML** と機能的に同等です：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n論理値属性を false に設定することは、その属性を使用しないことと同等です。論理式の値を使用することもできます：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nこれは次の **HTML** と機能的に同等です：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 文字列に似た属性\n\nいくつかの論理値属性に加えて、多くの文字列に似た HTML 属性を扱うことがあります。Yew には、文字列に似た値をコンポーネントに渡すためのいくつかのオプションがあります。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nそれらはすべて有効ですが、特にクローンを作成する必要がある場合や、別のコンポーネントに属性として渡す必要がある場合は、Yew のカスタム `AttrValue` を使用することをお勧めします。\n\n## HTML 要素のオプション属性\n\nほとんどの HTML 属性はオプションの値（Some(x) または None）を使用できます。これにより、属性がオプションとしてマークされている場合にその属性を省略できます。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n属性が `None` に設定されている場合、その属性は DOM に設定されません。\n\n## 関連例\n\n- [インライン HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/events.mdx",
    "content": "---\ntitle: 'イベント'\n---\n\n## 紹介\n\nYew は [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) クレートと統合されており、このクレートのイベントを使用します。以下の[表](#event-types)には、`html!` マクロで受け入れられるすべての `web-sys` イベントが一覧表示されています。\n\n下記の表に記載されていないイベントについても、[`Callback`](../function-components/callbacks.mdx) を追加してリッスンすることができます。詳細は[手動イベントリスナー](#manual-event-listener)を参照してください。\n\n## イベントタイプ\n\n:::tip\nすべてのイベントタイプは `yew::events` に再エクスポートされています。\n`yew::events` のタイプを使用することで、`web-sys` を手動でクレートに依存関係として追加するよりも、バージョン互換性を確保しやすくなります。\nYew が指定するバージョンと競合するバージョンを使用することがなくなります。\n:::\n\nイベントリスナーの名前は、`html` マクロでイベント `Callback` を追加する際に期待される名前です：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nイベント名はリスナー名から \"on\" プレフィックスを削除したもので、したがって `onclick` イベントリスナーは `click` イベントをリッスンします。ページの最後にある[完全なイベントリスト](#available-events)とそのタイプを参照してください。\n\n## イベントキャプチャ {#event-bubbling}\n\nYew がディスパッチするイベントは仮想 DOM 階層に従い、リスナーに向かってバブルアップします。現在、リスナーのバブルフェーズのみがサポートされています。仮想 DOM 階層は通常（ただし常にではありません）実際の DOM 階層と同じです。[ポータル](../../advanced-topics/portals)やその他の高度な技術を扱う際には、この違いが重要です。よく設計されたコンポーネントでは、直感的にイベントは子コンポーネントから親コンポーネントにバブルアップするはずです。これにより、`html!` で記述した階層がイベントハンドラによって観察される階層となります。\n\nイベントのバブルアップを避けたい場合は、アプリケーションを起動する前に以下のコードを呼び出すことができます\n\n```rust\nyew::set_event_bubbling(false);\n```\n\nアプリケーションを起動する*前に*。これによりイベント処理が高速化されますが、期待されるイベントを受信しないために一部のコンポーネントが動作しなくなる可能性があります。慎重に使用してください！\n\n## イベントデリゲート\n\n驚くかもしれませんが、イベントリスナーはレンダリングされた要素に直接登録されるわけではありません。代わりに、イベントは Yew アプリケーションのサブツリーのルートノードから委譲されます。ただし、イベントはそのネイティブ形式で渡され、合成形式は作成されません。これにより、HTML リスナーで予期されるイベントと Yew で発生するイベントとの間に不一致が生じる可能性があります。\n\n- [`Event::current_target`] はリスナーが追加された要素ではなく、Yew サブツリーのルートノードを指します。基になる `HtmlElement` にアクセスしたい場合は、[`NodeRef`](../function-components/node-refs.mdx) を使用してください。\n- [`Event::event_phase`] は常に [`Event::CAPTURING_PHASE`] です。内部的には、イベントはバブリングフェーズにあるかのように振る舞い、イベント伝播が再生され、イベントは[上位にバブルアップ](#event-bubbling)します。つまり、仮想 DOM 内の上位のイベントリスナーが下位のイベントリスナーの後にトリガーされます。現在、Yew はキャプチャリスナーをサポートしていません。\n\nこれも意味するところは、Yew によって登録されたイベントは通常、他のイベントリスナーよりも先にトリガーされるということです。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 型付きイベントターゲット\n\n:::caution\nこのセクションでは、**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** は常にイベントが発生した要素を指します。\n\nこれは**必ずしも** `Callback` が配置された要素を指すわけではありません。\n:::\n\nイベント `Callback` の中で、イベントのターゲットを取得したい場合があります。例えば、`change` イベントは何かが変更されたことを通知するだけで、具体的な情報を提供しません。\n\nYew では、正しい型でターゲット要素を取得する方法がいくつかあり、ここで順を追って説明します。イベント上の [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を呼び出すと、オプションの [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 型が返されますが、入力要素の値を知りたい場合にはあまり役に立たないかもしれません。\n\n以下のすべての方法で、同じ問題を解決します。これにより、方法の違いが明確になり、問題に対処することができます。\n\n**問題：**\n\n`<input>` 要素に `onchange` `Callback` があり、呼び出されるたびにコンポーネントに[更新](components#update) `Msg` を送信したいとします。\n\n`Msg` 列挙型は次のようになります：\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### `JsCast` の使用\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) クレートには便利なトレイトがあります：[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)。これにより、型が `JsCast` を実装している限り、型間の直接キャストが可能になります。慎重にキャストすることもできますが、これはランタイムチェックと `Option` や `Result` のロジックを処理することを伴います。また、強制的にキャストすることもできます。\n\nコードを見てみましょう：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# JsCast を呼び出すために wasm-bindgen が必要です\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // イベントが作成されたとき、ターゲットは未定義であり、ディスパッチされるときにのみターゲットが追加されます。\n            let target: Option<EventTarget> = e.target();\n            // イベントはバブルアップする可能性があるため、\n            // このリスナーは HtmlInputElement 型ではない子要素のイベントをキャッチする可能性があります。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // target が HtmlInputElement であることを理解している必要があります。\n        // そうでない場合、value を呼び出すと未定義の動作（UB）になります。\n        // ここでは、これが入力要素であることを確信しているため、チェックせずに適切な型に変換できます。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` が提供するメソッドは [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) と [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into) です。これらのメソッドを使用すると、`EventTarget` から [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html) への変換が可能になります。`dyn_into` メソッドは慎重で、実行時に型が実際に `HtmlInputElement` であるかどうかをチェックし、そうでない場合は `Err(JsValue)` を返します。[`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) は汎用型で、元のオブジェクトを返し、別の型への変換を再試行することができます。\n\nここで、危険なバージョンを使用するタイミングについて考えるかもしれません。上記のケースでは、子要素のない要素に `Callback` を設定しているため、ターゲットは同じ要素である必要があるため、安全です<sup>1</sup>。\n\n_<sup>1</sup> JS の領域に関わる限り、安全です。_\n\n### `TargetCast` の使用\n\n**[JsCast の使用](#using-jscast) を先に読むことを強くお勧めします！**\n\n:::note\n`TargetCast` は新しいユーザーが `JsCast` の動作を理解するために設計されていますが、範囲はイベントとそのターゲットに限定されています。\n\n`TargetCast` または `JsCast` を選択するのは純粋に個人の好みの問題であり、実際には `TargetCast` の実装と `JsCast` の機能は非常に似ています。\n:::\n\n`TargetCast` トレイトは `JsCast` の上に構築されており、イベントから型付きのイベントターゲットを取得するために特化されています。\n\n`TargetCast` は Yew の一部であるため、依存関係を追加せずにイベント上でトレイトメソッドを使用できますが、その動作は `JsCast` と非常に似ています。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // target が HtmlInputElement であることを理解している必要があります。\n        // そうでない場合、value を呼び出すと未定義の動作（UB）になります。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nもし `JsCast` についてすでに知っているか、このトレイトに精通している場合、`TargetCast::target_dyn_into` が `JsCast::dyn_into` に似ていることに気付くでしょうが、イベントのターゲットに特化しています。`TargetCast::target_unchecked_into` は `JsCast::unchecked_into` に似ているため、上記の `JsCast` に関するすべての警告が `TargetCast` にも適用されます。\n\n### `NodeRef` の使用\n\n[`NodeRef`](../function-components/node-refs.mdx) は、与えられたイベントを `Callback` に渡す代わりに使用できます。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`NodeRef` を使用すると、イベントを無視して `NodeRef::cast` メソッドを使用して `Option<HtmlInputElement>` を取得できます。これはオプションであり、`NodeRef` を設定する前に `cast` を呼び出すか、型が一致しない場合に `None` を返します。\n\n`NodeRef` を使用することで、常に `input_node_ref` にアクセスできるため、状態に `String` を送信する必要がないことがわかるかもしれません。したがって、次のようにすることができます：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // value に対して何かを行う\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nどの方法を選択するかは、コンポーネントと個人の好みによります。*推奨される*方法はありません。\n\n## 手動イベントリスナー\n\nYew の `html` マクロがサポートしていないイベントをリッスンしたい場合があります。サポートされているイベントのリストは[こちら](#event-types)を参照してください。\n\n手動で要素にイベントリスナーを追加するには、[`NodeRef`](../function-components/node-refs.mdx) を使用して、`use_effect_with` 内で [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) と [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API を使用してリスナーを追加します。\n\n以下の例では、架空の `custard` イベントにリスナーを追加する方法を示します。Yew がサポートしていないすべてのイベントやカスタムイベントは、[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) として表現できます。カスタム/サポートされていないイベントの特定のメソッドやフィールドにアクセスする必要がある場合は、[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) のメソッドを使用して必要な型に変換できます。\n\n### `Closure` を使用する（冗長バージョン）\n\n直接 `web-sys` と `wasm-bindgen` のインターフェースを使用するのは少し面倒かもしれません……なので、心の準備をしてください（[`gloo` のおかげで、より簡潔な方法があります](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 通常作成する Callback を作成\n                    let oncustard = Callback::from(move |_: Event| {\n                        // カスタードに対して何かを行う..\n                    });\n\n                    // Box<dyn Fn> から Closure を作成 - これは 'static である必要があります\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n`Closure` の詳細については、[wasm-bindgen ガイド](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html) を参照してください。\n\n### `gloo` を使用する（簡潔なバージョン）\n\nより便利な方法は、`gloo`、具体的には [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html) を使用することです。\nこれは `web-sys`、`wasm-bindgen` の高レベル抽象実装です。\n\n`gloo_events` は、イベントリスナーを作成および保存するために使用できる `EventListener` 型を提供します。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 通常作成する Callback を作成\n                    let oncustard = Callback::from(move |_: Event| {\n                        // カスタードに対して何かを行う..\n                    });\n\n                    // Box<dyn Fn> から Closure を作成 - これは 'static である必要があります\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n`EventListener` の詳細については、[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html) を参照してください。\n\n## 利用可能なイベントの完全なリスト {#available-events}\n\n| リスナー名                  | `web_sys` イベントの種類                                                              |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空のタグ (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロは常にルートノードを必要とします。この制限を回避するために、「空のタグ」（または fragments）を使用できます。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// エラー: ルート HTML 要素は1つだけ許可されます\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'HTML および SVG を生成するためのプロシージャルマクロ'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` マクロを使用すると、宣言的に HTML および SVG コードを記述できます。これは、JavaScript で HTML に似たコードを記述できる拡張機能である JSX に似ています。\n\n**重要な注意点**\n\n1. `html! {}` マクロは 1 つのルート HTML ノードしか受け入れません（これを回避するには、[fragments](./fragments.mdx) または [iterators](./../html/lists.mdx) を使用できます）\n2. 空の `html! {}` 呼び出しは有効で、何もレンダリングしません\n3. リテラルは常に引用符で囲み、中括弧で囲む必要があります：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` マクロはすべてのタグ名を小文字に変換します。大文字の文字（特定の SVG 要素に必要な文字）を使用するには、[動的タグ名](concepts/html/elements.mdx#dynamic-tag-names) を使用してください：`html! { <@{\"myTag\"}></@> }`\n\n:::note\n`html!` マクロはコンパイラのデフォルトの再帰制限に達する可能性があります。コンパイル エラーが発生した場合は、クレートのルートに `#![recursion_limit=\"1024\"]` のような属性を追加して問題を解決してください。\n:::\n\n## タグ (Tags) 構造\n\nタグ (Tags) は HTML タグに基づいています。コンポーネント、要素、およびリストはすべてこのタグ構文に基づいています。\n\nタグは自己閉鎖 `<... />` であるか、開始タグごとに対応する終了タグが必要です。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 閉じタグがありません\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 閉じタグがありません\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n便利のために、通常は閉じタグが必要な要素も**自己閉じ**が許可されています。例えば、`html! { <div class=\"placeholder\" /> }` と記述することができます。\n:::\n\n複雑なネストされた HTML および SVG レイアウトを作成するのは依然として簡単です：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nもし、Rust コンパイラの開発者バージョンを使用して Yew をコンパイルする場合、マクロは一般的な落とし穴について警告します。もちろん、安定版コンパイラを使用してリリースビルドを行う必要があるかもしれません（例えば、組織のポリシーでそうする必要がある場合など）。しかし、安定版ツールチェーンを使用している場合でも、`cargo +nightly check` を実行すると、HTML コードを改善する方法がいくつか示されるかもしれません。\n\n現在、これらのリントは主にアクセシビリティに関連しています。リントに関するアイデアがあれば、[この問題](https://github.com/yewstack/yew/issues/1334)に自由にコメントしてください。\n\n## 属性とプロパティの指定\n\n属性は通常の HTML と同じ方法で要素に設定されます：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n属性は要素名の前に `~` を使用して指定されます：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n値がリテラルの場合、値を囲む中括弧は省略できます。\n\n:::\n\n:::note リテラルとは\n\nリテラルは、Rust のすべての有効な[リテラル式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)です。注意してください、[負の数は**リテラルではありません**](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)、したがって中括弧で囲む必要があります `{-6}`。\n\n:::\n\n:::note コンポーネント属性\nコンポーネント属性は Rust オブジェクトとして渡され、ここで説明されている要素のパラメータ (Attributes) / 属性 (Properties) とは異なります。\n[コンポーネント属性](../function-components/properties.mdx)で詳細を確認してください。\n:::\n\n### 特殊属性\n\nいくつかの特殊な属性があり、これらは直接 DOM に影響を与えるのではなく、Yew 仮想 DOM の指示として機能します。現在、2 つの特殊な属性があります：`ref` と `key`。\n\n`ref` は、基礎となる DOM ノードに直接アクセスして操作することを可能にします。詳細については、[Refs](../function-components/node-refs.mdx)を参照してください。\n\n一方、`key` は要素に一意の識別子を提供し、Yew が最適化のために使用できます。\n\n:::info\n[詳細はこちら](./html/lists)\n:::\n\n## 条件付きレンダリング\n\nRust の条件構造を使用して、条件付きでマークアップをレンダリングできます。現在、`if` と `if let` のみがサポートされています。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n条件付きレンダリングの詳細については、[条件付きレンダリング](./conditional-rendering.mdx)のセクションを参照してください。\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/lists.mdx",
    "content": "---\ntitle: 'リスト'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## イテレータ\n\nイテレータから HTML を構築する方法は 3 つあります：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` ループ\">\n主なアプローチは for ループを使用することです。これは Rust に既に存在する for ループと同じですが、2 つの重要な違いがあります：\n1. 通常の for ループは何も返せませんが、`html!` 内の for ループはノードのリストに変換されます。\n2. `break`、`continue` などの発散式は `html!` 内の for ループの本体では許可されていません。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` ブロック\">\nもう一つの方法は `for` キーワードを使用することです。これはネイティブの Rust 構文ではなく、HTML マクロによってイテレータを表示するために必要なコードを出力します。\nこの方法は、イテレータが既に計算されていて、マクロに渡すだけでよい場合に最初の方法より適しています。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` メソッド\">\n\n最後の方法は、イテレータの最終変換で `collect::<Html>()` を呼び出すことで、Yew が表示できるリストを返します。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## キー付きリスト\n\nキー付きリストは、すべての子要素にキーがある最適化されたリストです。\n`key` は Yew が提供する特別な属性で、HTML 要素やコンポーネントに一意の識別子を与え、Yew 内部での最適化に使用されます。\n\n:::caution\nキーは各リスト内で一意である必要があり、HTML の `id` のようにグローバルに一意である必要はありません。リストの順序に依存してはいけません。\n:::\n\nリストにキーを追加することを常にお勧めします。\n\n一意の `String`、`str`、または整数を特別な `key` 属性に渡すことでキーを追加できます。\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### パフォーマンスの最適化\n\nキー付きリストのパフォーマンス向上をテストするための[例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)があります。以下は簡単なテスト手順です：\n\n1. [オンラインデモ](https://examples.yew.rs/keyed_list)にアクセスします。\n2. 500個の要素を追加します。\n3. キーを無効にします。\n4. リストを反転します。\n5. \"最後のレンダリングにかかった時間 Xms\" を確認します（この記事の執筆時点では約60ms）。\n6. キーを有効にします。\n7. 再度リストを反転します。\n8. \"最後のレンダリングにかかった時間 Xms\" を確認します（この記事の執筆時点では約30ms）。\n\nこの記事の執筆時点では、500個のコンポーネントに対して速度が2倍に向上しました。\n\n### 原理の説明\n\n通常、リストを反復処理する際には、各リスト項目にキーを追加するだけで済みます。データの順序が変わる可能性があるためです。\nリストを再レンダリングする際に、キーは調整プロセスを高速化するために使用されます。\n\nキーがない場合、例えば `[\"bob\", \"sam\", \"rob\"]` を反復処理すると、最終的に以下のようなHTMLが生成されます：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n次のレンダリングでリストが `[\"bob\", \"rob\"]` に変更された場合、Yew は id=\"rob\" の要素を削除し、id=\"sam\" を id=\"rob\" に更新できます。\n\n各要素にキーを追加すると、初期の HTML は変わりませんが、変更後のリスト `[\"bob\", \"rob\"]` をレンダリングすると、Yew は2番目の HTML 要素のみを削除し、他の要素はそのまま残ります。キーを使用して要素を関連付けることができるためです。\n\nコンポーネントから別のコンポーネントに切り替える際に、両方に最高レンダリング要素として div がある場合にバグ/\"機能\" に遭遇した場合。\nYew はこれらの状況で最適化として既にレンダリングされた HTML div を再利用します。\nその div を再利用せずに再作成する必要がある場合は、異なるキーを追加することで再利用されなくなります。\n\n## さらなる読み物\n\n- [TodoMVC の例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [キー付きリストの例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [ルーティングの例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'リテラルと式'\n---\n\n## リテラル\n\n式が `Display` を実装する型に解決される場合、それらは文字列に変換され、[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) ノードとしてDOMに挿入されます。\n\n:::note\n文字列リテラルは `Text` ノードを作成し、ブラウザはそれを文字列として扱います。そのため、式に `<script>` タグが含まれていても、式を `<script>` ブロックでラップしない限り、XSS などのセキュリティ問題に遭遇することはありません。\n:::\n\nすべての表示テキストは式と見なされるため、`{}` ブロックで囲む必要があります。これは、Yew と通常の HTML 構文の最大の違いです。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 式\n\n`{}` ブロックを使用して、HTML 内に式を挿入できます。それらが `Html` に解決される限り。\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常、これらの式を関数やクロージャに抽出して、可読性を最適化することが意味があります：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/router.mdx",
    "content": "---\ntitle: 'ルーター (Router)'\ndescription: 'Yew の公式ルーターライブラリ'\n---\n\nシングルページアプリケーション (SPA) のルーターは、URL に基づいて異なるページを表示する処理を行います。リンクをクリックしたときに異なるリモートリソースを要求するデフォルトの動作とは異なり、ルーターはアプリケーション内の有効なルートを指すようにローカルで URL を設定します。その後、ルーターはこの変更を検出し、レンダリングする内容を決定します。\n\nYew は `yew-router` クレートでルーターサポートを提供します。使用を開始するには、依存関係を `Cargo.toml` ファイルに追加してください。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n必要なツールはすべて `yew_router::prelude` モジュールで提供されています。\n\n## 使用方法\n\nまず、`Route` を定義する必要があります。\n\nルートは `Routable` を派生する `enum` で定義されます。この列挙型は `Clone + PartialEq` を実装する必要があります。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` と `<Switch />` コンポーネントはペアで使用され、後者はブラウザの現在の URL に一致するパスのバリアントを見つけ、それを `render` コールバックに渡します。その後、コールバックがレンダリングする内容を決定します。パスが一致しない場合、ルーターは `not_found` 属性を持つパスにナビゲートします。指定されたルートがない場合、何もレンダリングされず、一致するルートがないことを示すメッセージがコンソールに記録されます。\n\nyew-router のほとんどのコンポーネント、特に `<Link />` と `<Switch />` は、ある Router コンポーネント（例： `<BrowserRouter />`）の（深い）子要素である必要があります。通常、アプリケーションには 1 つの Router しか必要なく、通常は最上位の `<App />` コンポーネントによって直ちにレンダリングされます。Router はコンテキストを登録し、これは Links と Switches の機能に必要です。以下に例を示します。\n\n:::caution\nブラウザ環境で `yew-router` を使用する場合、`<BrowserRouter />` を強く推奨します。他のルータータイプについては [API リファレンス](https://docs.rs/yew-router/) を参照してください。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### パスセグメント\n\nルーターは、動的および名前付きワイルドカードセグメントを使用してルートから情報を抽出することもできます。次に、`<Switch />` 内で投稿の ID にアクセスし、それを適切なコンポーネントにプロパティとして渡すことができます。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n`Post {id: String}` の代わりに通常の `Post` バリアントを使用することもできます。例えば、`Post` が別のルーターと一緒にレンダリングされる場合、そのフィールドは冗長になる可能性があります。詳細については、以下の[ネストされたルーター](#nested-router)セクションを参照してください。\n:::\n\nフィールドは `Route` 列挙型の一部として `Clone + PartialEq` を実装する必要があることに注意してください。また、シリアル化と逆シリアル化のために `std::fmt::Display` と `std::str::FromStr` を実装する必要があります。整数、浮動小数点数、および文字列などのプリミティブ型はこれらの要件を既に満たしています。\n\nパスの形式が一致しても、逆シリアル化が失敗した場合（`FromStr` に基づく）、ルーターはルートが一致しないと見なし、見つからないルートをレンダリングしようとします（または、見つからないルートが指定されていない場合は空白ページをレンダリングします）。\n\n以下の例を参照してください：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch 関数は News と id をレンダリングします。ここでは省略されています。\n```\n\nセグメントが 255 を超えると、`u8::from_str()` は失敗し、`ParseIntError` を返します。この場合、ルーターはルートが一致しないと見なします。\n\n![ルーターの逆シリアル化失敗の動作](/img/router-deserialization-failure-behavior.gif)\n\nルーティング構文やパラメータのバインディング方法の詳細については、[route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params) を参照してください。\n\n### 位置 (Location)\n\nルーターはコンテキストを介して一般的な `Location` 構造体を提供し、ルート情報にアクセスするために使用できます。これらはフックまたは `ctx.link()` 上の便利な関数を介して取得できます。\n\n### ナビゲーション\n\n`yew_router` はナビゲーションを処理するためのいくつかのツールを提供します。\n\n#### リンク\n\n`<Link />` は `<a>` 要素としてレンダリングされ、`onclick` イベントハンドラは [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) を呼び出し、ターゲットページを履歴にプッシュして必要なページをレンダリングします。これはシングルページアプリケーションに期待される動作です。通常のアンカー要素のデフォルトの `onclick` はページをリロードします。\n\n`<Link />` コンポーネントはその子要素を `<a>` 要素に渡します。これはアプリ内ルーティングのための `<a/>` の代替として考えることができます。違いは、`href` の代わりに `to` 属性を提供する必要があることです。使用例は以下の通りです：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n構造体変数も正常に動作します：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### ナビゲーションインターフェース\n\nナビゲーター API は、関数コンポーネントと構造体コンポーネントの両方で提供されます。これにより、コールバックがルートを変更できるようになります。どちらの場合でも、`Navigator` インスタンスを取得してルートを操作できます。\n\n##### 関数コンポーネント\n\n関数コンポーネントの場合、基礎となるナビゲータープロバイダーが変更されると、`use_navigator` フックはコンポーネントを再レンダリングします。\n以下は、クリック時に `Home` ルートにナビゲートするボタンを実装する例です。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\nここでの例では `Callback::from` を使用しています。ターゲットルートがコンポーネントのルートと同じになる可能性がある場合、または安全のために、通常のコールバックを使用してください。例えば、各ページにロゴボタンがあり、そのボタンをクリックするとホームに戻るとします。ホームページでそのボタンを2回クリックすると、同じHomeルートがプッシュされ、`use_navigator` フックが再レンダリングをトリガーしないため、コードがクラッシュします。\n:::\n\n現在の位置をスタックに新しい位置としてプッシュするのではなく置き換えたい場合は、`navigator.push()` の代わりに `navigator.replace()` を使用してください。\n\n`navigator` はコールバックに移動する必要があるため、他のコールバックで再利用できないことに気付くかもしれません。幸いなことに、`navigator` は `Clone` を実装しているため、異なるルートに対して複数のボタンを設定する方法は次のとおりです：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 構造体コンポーネント\n\n構造体コンポーネントの場合、`ctx.link().navigator()` API を使用して `Navigator` インスタンスを取得できます。残りの部分は関数コンポーネントの場合と同じです。以下は、単一のボタンをレンダリングするビュー関数の例です。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### リダイレクト\n\n`yew-router` は prelude に `<Redirect />` コンポーネントも提供しています。これはナビゲーター API と同様の効果を実現するために使用できます。このコンポーネントは、ターゲットルートとして `to` 属性を受け取ります。`<Redirect/>` がレンダリングされると、ユーザーは指定されたルートにリダイレクトされます。以下はその例です：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // `use_user` フックを使用してユーザーを取得\n    let user = match use_user() {\n        Some(user) => user,\n        // ユーザーが `None` の場合、ログインページにリダイレクト\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 実際のページ内容\n}\n```\n\n:::tip `Redirect` と `Navigator` の選択方法\nNavigator API はコールバック内でルートを操作する唯一の方法です。\n一方、`<Redirect />` はコンポーネント内の戻り値として使用できます。また、[ネストされたルーター](#nested-router)の switch 関数など、他の非コンポーネントコンテキストでも `<Redirect />` を使用することができます。\n:::\n\n### 変更のリスニング\n\n#### 関数コンポーネント\n\n`use_location` と `use_route` フックを使用できます。提供された値が変更されると、コンポーネントが再レンダリングされます。\n\n#### 構造体コンポーネント\n\nルートの変更に応答するために、`ctx.link()` の `add_location_listener()` メソッドにコールバッククロージャを渡すことができます。\n\n:::note\n位置リスナーが削除されると、それは登録解除されます。ハンドルをコンポーネントの状態に保存することを確認してください。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // イベントを処理する\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` と `ctx.link().route::<R>()` も、一度だけ位置とルートを取得するために使用できます。\n\n### クエリパラメータ\n\n#### ナビゲーション時にクエリパラメータを指定する\n\n新しいルートにナビゲートする際にクエリパラメータを指定するには、`navigator.push_with_query` または `navigator.replace_with_query` 関数を使用します。これは `serde` を使用してパラメータを URL のクエリ文字列にシリアル化するため、`Serialize` を実装している任意の型を渡すことができます。最も簡単な形式は文字列ペアを含む `HashMap` です。\n\n#### 現在のルートのクエリパラメータを取得する\n\nクエリパラメータを取得するには、`location.query` を使用します。これは `serde` を使用して URL のクエリ文字列からパラメータを逆シリアル化します。\n\n## ネストされたルーター\n\nアプリケーションが大きくなると、ネストされたルーターが役立つ場合があります。次のルーター構造を考えてみましょう：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nネストされた `SettingsRouter` は、すべての `/settings` で始まる URL を処理します。また、一致しない URL をメインの `NotFound` ルートにリダイレクトします。したがって、`/settings/gibberish` は `/404` にリダイレクトされます。\n\n:::caution\n\nこのインターフェースはまだ開発中であり、このように記述する方法は最終決定されていません。\n\n:::\n\n以下のコードで実装できます：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### ベースパス (Basename)\n\n`yew-router` を使用してベースパス (Basename) を定義できます。\nベースパスはすべてのルートの共通プレフィックスです。ナビゲーター API と `<Switch />` コンポーネントはどちらもベースパスの設定をサポートしています。プッシュされるすべてのルートにはベースパスのプレフィックスが追加され、すべてのスイッチはパスを `Routable` に解析する前にベースパスを削除します。\n\nRouter コンポーネントにベースパス属性が提供されていない場合、HTML ファイルの `<base />` 要素の href 属性を使用し、HTML ファイルに `<base />` 要素がない場合は `/` にフォールバックします。\n\n## 関連例\n\n- [ルーター](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## インターフェースリファレンス\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/concepts/suspense.mdx",
    "content": "---\ntitle: 'サスペンス (Suspense)'\ndescription: 'データ取得のためのサスペンス'\n---\n\nサスペンス (Suspense) は、タスクが完了するまでコンポーネントのレンダリングを一時停止し、その間にフォールバック（プレースホルダー）UI を表示する方法です。\n\nこれは、サーバーからデータを取得したり、プロキシがタスクを完了するのを待ったり、他のバックグラウンド非同期タスクを実行したりするために使用できます。\n\nサスペンスが表示される前に、データ取得は通常、コンポーネントのレンダリング後（レンダリング時取得）またはレンダリング前（取得後レンダリング）に発生します。\n\n### レンダリングしながらダウンロード\n\nサスペンス (Suspense) は、新しい方法を提供し、コンポーネントがレンダリング中にデータリクエストを発行できるようにします。コンポーネントがデータリクエストを発行すると、レンダリングプロセスが一時停止され、リクエストが完了するまでフォールバック UI が表示されます。\n\nサスペンスを使用するには、フック (Hook) を使用することをお勧めします。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n上記の例では、`use_user` フックはユーザー情報の読み込み中にコンポーネントのレンダリングを一時停止し、`user` が読み込まれる前に `Loading...` プレースホルダーを表示します。\n\nコンポーネントのレンダリングを一時停止するフックを定義するには、`SuspensionResult<T>` を返す必要があります。コンポーネントが一時停止する必要がある場合、フックは `Err(Suspension)` を返すべきであり、ユーザーはそれを `?` でアンパックする必要があります。これにより、それが `Html` に変換されます。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // ユーザーが読み込まれたら、それを Ok(user) として返します。\n        Some(user) => Ok(user),\n        None => {\n            // ユーザーがまだ読み込まれていない場合、`Suspension` を作成し、\n            // データの読み込みが完了したときに `SuspensionHandle::resume` を呼び出します。\n            // これにより、コンポーネントは自動的に再レンダリングされます。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### サスペンスフック (Hook) の実装に関する注意事項\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) は 2 つの値を返します：サスペンスコンテキスト自体とサスペンスハンドル。後者はサスペンスされたコンポーネントを再レンダリングするタイミングを管理し、2 つの方法で操作できます：\n\n1. その [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) メソッドを呼び出す。\n2. ハンドルを破棄する。\n\n:::danger\n\nサスペンスハンドルは、新しいデータを受け取ってコンポーネントを更新するまで保存する必要があります。そうしないと、サスペンスされたコンポーネントが無限再レンダリングループに入り、パフォーマンスに影響を与えます。\n上記の例では、サスペンスハンドルはクロージャに移動し、`on_load_user_complete` に渡されることで保存されます。\n仮想ユーザーが読み込まれると、クロージャが呼び出され、`handle.resume()` が呼び出され、サスペンスコンテキストに関連するコンポーネントが再レンダリングされます。\n\n:::\n\n# 完全な例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 省略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 省略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // ユーザーが読み込まれたら、それを Ok(user) として返します。\n        Some(user) => Ok(user),\n        None => {\n            // ユーザーがまだ読み込まれていない場合、`Suspension` を作成し、\n            // データの読み込みが完了したときに `SuspensionHandle::resume` を呼び出します。\n            // これにより、コンポーネントは自動的に再レンダリングされます。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 構造体コンポーネントでプレースホルダーを使用する\n\n構造体コンポーネントを直接サスペンドすることはできません。しかし、関数コンポーネントを[高階コンポーネント](../advanced-topics/struct-components/hoc)として使用し、プレースホルダーに基づいたデータ取得を実現することができます。\n\nYew リポジトリの[プレースホルダーの例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)は、このコンポーネントの使用方法を示しています。\n\n## 関連例\n\n- [プレースホルダー](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'サンプルアプリケーションの構築'\n---\n\n環境が整ったら、基本的な Yew アプリケーションに必要なテンプレートを使用するか、小さなプロジェクトを手動で設定することができます。\n\n## テンプレートを使用して迅速に開始\n\n[`cargo-generate`](https://github.com/cargo-generate/cargo-generate) のインストール手順に従ってツールをインストールし、次のコマンドを実行します：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手動でアプリケーションを設定する\n\n### プロジェクトの作成\n\nまず、新しい cargo プロジェクトを作成してください。\n\n```bash\ncargo new yew-app\n```\n\n新しく作成したディレクトリを開きます。\n\n```bash\ncd yew-app\n```\n\n### Hello World サンプルを実行する\n\nRust 環境が正しく設定されているかを確認するために、`cargo run` を使用して初期プロジェクトを実行します。\"Hello World!\" メッセージが表示されるはずです。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### プロジェクトを Yew Web アプリケーションに設定する\n\nこのシンプルなコマンドラインアプリケーションを基本的な Yew Web アプリケーションに変換するために、いくつかの変更が必要です。\n\n#### Cargo.toml の更新\n\n依存関係リストに `yew` を追加します。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\nアプリケーションを構築するだけの場合は、`csr` 特性のみが必要です。これにより、`Renderer` とクライアントサイドレンダリングに関連するすべてのコードが有効になります。\n\nライブラリを作成している場合は、この特性を有効にしないでください。クライアントサイドレンダリングロジックがサーバーサイドレンダリングパッケージに含まれることになります。\n\nテストやサンプルのために Renderer が必要な場合は、`dev-dependencies` で有効にするべきです。\n\n:::\n\n#### main.rs の更新\n\nテンプレートを生成し、クリック時に値を更新するボタンをレンダリングする `App` という名前のルートコンポーネントを設定する必要があります。以下のコードで `src/main.rs` の内容を置き換えます。\n\n:::note\n`main` 関数内の `yew::Renderer::<App>::new().render()` 呼び出しは、アプリケーションを起動し、ページの `<body>` タグにマウントします。動的なプロパティを使用してアプリケーションを起動したい場合は、`yew::Renderer::<App>::with_props(..).render()` を使用できます。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### index.html の作成\n\n最後に、アプリケーションのルートディレクトリに `index.html` ファイルを追加します。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## アプリケーションの表示\n\n以下のコマンドを実行して、ローカルでアプリケーションをビルドおよび提供します。\n\n```bash\ntrunk serve\n```\n\n:::info\n`--open` オプションを追加して、デフォルトのブラウザを開くことができます：`trunk serve --open`。\n:::\n\nTrunk は、ソースコードファイルを変更するたびにアプリケーションをリアルタイムで再構築します。\nデフォルトでは、サーバーはアドレス '127.0.0.1' のポート '8080' でリッスンします => [http://localhost:8080](http://127.0.0.1:8080)。\nこの設定を変更するには、次のファイルを作成して必要に応じて編集してください：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# ローカルネットワーク上のリッスンアドレス\naddress = \"127.0.0.1\"\n# 広域ネットワーク上のリッスンアドレス\n# address = \"0.0.0.0\"\n# リッスンするポート\nport = 8000\n```\n\n## おめでとうございます\n\nこれで、Yew 開発環境の設定が完了し、最初の Web アプリケーションを構築できました。\n\nこのアプリケーションを試してみて、さらに学習するために[サンプル](./examples.mdx)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'エディタの設定'\ndescription: 'コードエディタの設定'\n---\n\n:::important 改善ドキュメント\n異なるエディタを使用していますか？おすすめがあれば、選択したエディタの説明を自由に追加してください。\n:::\n\n## コンポーネント作成のためのテンプレートを追加\n\n### JetBrains IDEs\n\n1. ナビゲーションバーから順に File | Settings | Editor | Live Templates をクリックします。\n2. Rust を選択し、+ アイコンをクリックして新しい Live Template を追加します。\n3. 必要に応じて名前と説明を入力します。\n4. 以下のコードスニペットをテンプレートテキスト部分に貼り付けます。\n5. 右下の適用範囲を変更し、Rust > Item > Module を選択します。\n\n関数型コンポーネントの場合、以下のテンプレートを使用します。\n\n- (オプション) 変数を編集し、`tag` に適切なデフォルト値（例：\"div\"）を設定します。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n構造体コンポーネントの場合、以下のより複雑なテンプレートを使用できます。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. ナビゲーションバーから順に File > Preferences > User Snippets をクリックします。\n2. 設定言語として Rust を選択します。\n3. 以下の JSON ファイルにコードスニペットを追加します。\n\n````json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n## `html!` マクロのサポート\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 拡張機能\n\n> これは**進行中の**、**コミュニティが維持している**プロジェクトです！[詳細を確認し、関連するバグ報告/問題/質問を直接拡張機能のリポジトリに送信してください](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 拡張機能は [VSC Marketplace で見つけることができます](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)、シンタックスハイライト、リネーム、ホバーなどの機能を提供します。\n\nEmmet サポートは直接使用できるはずですが、できない場合は `settings.json` ファイルを編集してください：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n````\n\n### Neovim\n\n#### Lazyvim\n\n> 以下の設定は [LazyVim](https://www.lazyvim.org) 設定および lazy.vim プラグインに適用されます。`lua/plugins/nvim-lspconfig.lua` にファイルを作成するか、既存の `lspconfig` を更新してください：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/getting-started/examples.mdx",
    "content": "---\ntitle: '例'\n---\n\nYew リポジトリには多くの[例]（メンテナンス状態はさまざま）があります。\nフレームワークのさまざまな機能を理解するために、それらを参照することをお勧めします。\n無視されがちで助けが必要な場合に備えて、プルリクエストや問題も歓迎します ♥️。\n\n詳細については、[README] を参照してください。\n\n:::note\nほとんどの例には、https://examples.yew.rs/< example_name > で見つけることができるオンラインデプロイがあります。\nそれぞれのサブフォルダーの README ページでバッジをクリックして、オンラインデモに移動します。\n:::\n\n[例のリスト]: https://github.com/yewstack/yew/tree/master/examples\n[例のドキュメント README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/getting-started/introduction.mdx",
    "content": "---\ntitle: '始めに'\n---\n\nYew アプリケーションをコンパイル、ビルド、パッケージ、およびデバッグするためにいくつかのツールが必要です。最初に、[Trunk](https://trunkrs.dev/) を使用することをお勧めします。Trunk は Rust 用の WASM Web アプリケーションパッケージツールです。\n\n## Rust のインストール\n\nRust をインストールするには、[公式の手順](https://www.rust-lang.org/tools/install) に従ってください。\n\n:::important\nYew がサポートする最低 Rust バージョン（MSRV）は `1.84.0` です。古いバージョンではコンパイルできません。`rustup show`（「active toolchain」の下）または `rustc --version` を使用してツールチェーンのバージョンを確認できます。ツールチェーンを更新するには、`rustup update` を実行してください。\n:::\n\n## WebAssembly ターゲットのインストール\n\nRust は異なる「ターゲット」（例えば異なるプロセッサ）に対してソースコードをコンパイルできます。ブラウザベースの WebAssembly 用のコンパイルターゲットは `wasm32-unknown-unknown` と呼ばれます。以下のコマンドは、開発環境に WebAssembly ターゲットを追加します。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Trunk のインストール\n\nTrunk は、デプロイとパッケージ管理に推奨されるツールであり、ドキュメントやサンプル全体で使用されています。\n\n```shell\n# 注意：これはすべての内容をゼロからコンパイルするため、インストールに時間がかかる場合があります\n# Trunk は多くの主要なパッケージマネージャーに対して事前構築されたバイナリを提供しています\n# 詳細については、https://trunkrs.dev/#install を参照してください\ncargo install --locked trunk\n```\n\n### 他のオプション\n\nTrunk の他にも、Yew アプリケーションをパッケージ化するための他のオプションがあります。以下のオプションのいずれかを試してみることをお勧めします：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/)（まだ初期開発段階です）\n\n## 次のステップ\n\n開発環境の設定が完了したら、ドキュメントの読み進めを続けることができます。実践を通じて学ぶのが好きな方は、[チュートリアル](../tutorial)をチェックすることをお勧めします。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: '0.22.0 から 0.23.0 へ'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` が同一ディスパッチで再レンダリングしなくなりました\n\n`use_reducer` はリデューサーが同じ `Rc` を返した場合（ポインタの同一性で判定）、再レンダリングをスキップするようになりました。以前は、すべてのディスパッチで再レンダリングが発生していました。\n\nリデューサーに `self` をそのまま返すコードパスがあり、それによる再レンダリングに依存していた場合は、`use_force_update` に置き換えてください:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"変更前\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // 0.23 ではこれは再レンダリングを発生させません!\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"リフレッシュ\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"変更後\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"リフレッシュ\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: '0.4.0 から 0.5.0 へ'\n---\n\n破壊的変更はありません。`Cargo.toml` で yew-agent を 0.5.0 に更新してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: '0.19.0 から 0.20.0 へ'\n---\n\n破壊的変更はありません。`Cargo.toml` で yew-router を 0.20.0 に更新してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nYew に CSS サポートを統合する最良の方法についての議論は、こちらで見つけることができます：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\nここには、Yew に CSS サポートを統合する最良の方法についての多くの議論が含まれています。\n\n現在、私たちが採用している方法は、開発者が最も人気のあるシステムを採用する前に多くのシステムを構築することを奨励することです。\n\nコミュニティは現在、プロジェクトにスタイルを追加するためのいくつかのプロジェクトを開発しています。以下はその一部です：\n\n#### コンポーネントライブラリ\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - JavaScript 依存なしの Yew スタイルフレームワーク。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - マテリアルデザインコンポーネント。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS コンポーネント。\n- [Yewtify](https://github.com/yewstack/yewtify) – Yew で Vuetify フレームワークの機能を実現。\n\n#### スタイルソリューション\n\n- [stylist](https://github.com/futursolo/stylist-rs) - WebAssembly アプリケーション用の CSS-in-Rust スタイルソリューション。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind ユーティリティクラス。\n\n:::important ドキュメントの改善\nYew にスタイルを追加するプロジェクトを開発している場合は、このリストに自分を追加する PR を提出してください！\n:::\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/more/debugging.mdx",
    "content": "---\ntitle: 'デバッグ'\n---\n\n## パニック (Panics)\n\nYew はブラウザのコンソールにパニックログを自動的に出力します。\n\n## コンソールログ\n\nJavaScript では、`console.log()` を使用してブラウザのコンソールに出力します。以下は Yew のいくつかのオプションです。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` クレートは [`log`](https://crates.io/crates/log) クレートと統合されており、ログレベル、ソース行、ファイル名をブラウザのコンソールに送信します。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nこのクレートは Gloo の一部で、ブラウザ API の Rust ラッパーを提供します。`log!` マクロは `JsValue` を直接受け入れることができ、`wasm_logger` よりも使いやすいです。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` は [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) と一緒に使用でき、メッセージをブラウザのコンソールに出力します。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## コンポーネントライフサイクルのデバッグ\n\n[`tracing`](https://crates.io/crates/tracing) は、コンポーネントのライフサイクルに関連するイベント情報を収集するために使用できます。`tracing` には `log` サポートの機能フラグもあり、`wasm-logger` とうまく統合できます。\n\n[コンパイル時フィルタ](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) は、詳細度を調整したりログ記録を無効にしたりするために使用できます。これにより、より小さな Wasm ファイルが生成されるはずです。\n\n## ソースマップ (Source Maps)\n\n[ソースマップ](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) をサポートするいくつかの方法がありますが、いくつかの設定が必要です。\n\n## 過去の記事\n\n以下は、Rust における WebAssembly デバッグの現状に関する過去の記事です。興味深い読み物かもしれません。\n\n\\[2019 年 12 月\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> これらの作業にはまだ多くのことが残されています。例えば、ツールの面では、Emscripten（Binaryen）と wasm-pack（wasm-bindgen）は、それらが実行する変換に対して DWARF 情報を更新することをまだサポートしていません。\n\n\\[2020 年\\] [Rust Wasm デバッグガイド](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 残念ながら、WebAssembly のデバッグ機能はまだ未成熟です。ほとんどの Unix システムでは、[DWARF](http://dwarfstd.org/) が実行中のプログラムのソースレベルの検査に必要な情報をエンコードするために使用されますが、Windows では同様の情報をエンコードする代替フォーマットがあります。しかし、現在のところ、WebAssembly には対応するフォーマットがありません。\n\n\\[2019 年\\] [Rust Wasm ロードマップ](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> デバッグは難しいです。なぜなら、多くの状況がこの作業グループの管理下にないからです。これは、WebAssembly の標準化機関やブラウザ開発者ツールを実装する人々に依存しています。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/more/deployment.mdx",
    "content": "---\ntitle: 'デプロイ'\ndescription: 'Yew アプリケーションのデプロイ'\n---\n\nYew アプリケーションをサーバーにデプロイする準備ができたら、いくつかのデプロイオプションがあります。\n\n`trunk build --release` は、リリースモードでアプリケーションをビルドします。HTTP サーバーを設定して、サイトにアクセスしたときに `index.html` を提供し、静的パス（例：`index_<hash>.js` および `index_bg_<hash>.wasm`）のリクエストに対して trunk が生成した dist ディレクトリから適切なコンテンツを提供する必要があります。\n\n:::important `trunk serve --release` について\n`trunk serve --release` を使用してアプリケーションを提供しないでください。\nこれは開発中にリリースビルドをテストするためだけに使用されるべきです。\n:::\n\n## サーバー設定\n\n### `index.html` をフォールバックとして提供する\n\nアプリケーションが [Yew ルーター](concepts/router.mdx) を使用している場合、存在しないファイルへのリクエスト時にサーバーが `index.html` を返すように設定する必要があります。\n\nYew ルーターを使用するアプリケーションは [シングルページアプリケーション (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA) として構築されています。ユーザーが実行中のクライアントから URL にナビゲートすると、ルーターが URL を解釈してそのページにルーティングします。\n\nしかし、ページをリフレッシュしたり、アドレスバーに URL を入力したりすると、これらの操作は実行中のアプリケーションではなく、ブラウザー自体によって処理されます。ブラウザーはその URL を直接サーバーにリクエストし、ルーターをバイパスします。誤って設定されたサーバーは 404 - 見つかりません 状態を返します。\n\n`index.html` を返すことで、アプリケーションは通常通りにロードされ、ルーターがルート `/show/42` を認識して適切なコンテンツを表示するまで、リクエストが `/` であるかのように動作します。\n\n### Web Assembly リソースに正しい MIME タイプを設定する\n\nWASM ファイルは `application/wasm` MIME タイプで [Content-Type ヘッダー](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) を設定する必要があります。\n\nほとんどのサーバーとホスティングサービスはデフォルトでこれを行います。サーバーがこれを行わない場合は、そのドキュメントを参照してください。ほとんどの Web ブラウザーでは、誤った MIME タイプは次のようなエラーを引き起こします：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 相対パスのビルド\n\nデフォルトでは、trunk はサイトが `/` で提供されると仮定し、それに応じてサイトをビルドします。この動作は、`index.html` ファイルに `<base data-trunk-public-url />` を追加することで上書きできます。Trunk はこのタグを書き換えて、`--public-url` に渡された値を含めます。Yew ルーターは `<base />` の存在を自動的に検出し、適切に処理します。\n\n## 環境変数を使用して動作をカスタマイズする\n\n通常、環境変数を使用してビルド環境をカスタマイズします。アプリケーションがブラウザで実行されるため、実行時に環境変数を読み取ることはできません。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) マクロは、コンパイル時に環境変数の値を取得できます。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/more/roadmap.mdx",
    "content": "---\ntitle: 'ロードマップ'\ndescription: 'Yew フレームワークの計画機能ロードマップ'\n---\n\n## 優先順位\n\nフレームワークの今後の機能と重点の優先順位はコミュニティによって決定されます。\n2020 年春に、プロジェクトの方向性に関するフィードバックを収集するために開発者調査を実施しました。\n調査の概要は [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) で確認できます。\n\n:::note\nすべての主要なイニシアチブのステータスは Yew Github の [プロジェクトボード](https://github.com/yewstack/yew/projects) で追跡できます。\n:::\n\n## 重点\n\n1. 最も人気のある機能\n2. プロダクションレディ\n3. ドキュメント\n4. 痛点\n\n### 最も人気のある機能\n\n1. [関数コンポーネント](https://github.com/yewstack/yew/projects/3)\n2. [コンポーネントライブラリ](https://github.com/yewstack/yew/projects/4)\n3. より良い状態管理\n4. [サーバーサイドレンダリング](https://github.com/yewstack/yew/projects/5)\n\n### プロダクションレディに必要な問題\n\n- Yew のテストカバレッジを向上させる\n- バイナリサイズを小さくする\n- [パフォーマンスベンチマーク](https://github.com/yewstack/yew/issues/5)\n\n### ドキュメント\n\n- チュートリアルを作成する\n- プロジェクト設定を簡素化する\n\n### 痛点\n\n- [コンポーネントテンプレート](https://github.com/yewstack/yew/issues/830)\n- [エージェント](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/more/testing.mdx",
    "content": "---\ntitle: 'アプリケーションのテスト'\ndescription: 'アプリケーションをテストする'\n---\n\n:::info\nコンポーネントのテストをより簡単にするために努力していますが、現在進行中です。\n\n[浅いレンダリング](https://github.com/yewstack/yew/issues/1413) のサポートは GitHub リポジトリで見つけることができます。\n:::\n\n## スナップショットテスト\n\nYew はコンポーネントのスナップショットテストを容易にするために `yew::tests::layout_tests` モジュールを提供しています。\n\n:::important ドキュメントの改善\nスナップショットテストのドキュメントを改善するための助けが必要です。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM ワーキンググループは [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) というクレートを維持しています。\nこれにより、組み込みの `#[test]` プロシージャマクロに似た方法でブラウザ内でテストを実行できます。\nこのモジュールの詳細については、[Rust Wasm ワーキンググループのドキュメント](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23/tutorial/index.mdx",
    "content": "---\ntitle: 'チュートリアル'\nslug: /tutorial\n---\n\n## 紹介\n\nこの実践チュートリアルでは、Yew を使用して Web アプリケーションを構築する方法を学びます。\n**Yew** は、[WebAssembly](https://webassembly.org/) を使用してフロントエンド Web アプリケーションを構築するためのモダンな [Rust](https://www.rust-lang.org/) フレームワークです。\nYew は Rust の強力な型システムを活用し、再利用可能で保守しやすく、良好に構造化されたアーキテクチャを奨励します。\nRust の [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html) と呼ばれるライブラリのエコシステムは、状態管理などの一般的なパターンのためのコンポーネントを提供します。\nRust のパッケージマネージャー [Cargo](https://doc.rust-lang.org/cargo/) を使用すると、Yew などの多くの crate を [crates.io](https://crates.io) から利用できます。\n\n### 構築する内容\n\nRustconf は、Rust コミュニティが毎年開催する星間集会です。\nRustconf 2020 には多くの講演があり、大量の情報が提供されました。\nこの実践チュートリアルでは、他の Rustaceans がこれらの講演を理解し、1つのページから視聴できるようにする Web アプリケーションを構築します。\n\n## セットアップ\n\n### 前提条件\n\nこのチュートリアルは、Rust に精通していることを前提としています。Rust の初心者である場合、無料の [Rust 本](https://doc.rust-lang.org/book/ch00-00-introduction.html) は初心者にとって素晴らしい出発点であり、経験豊富な Rust 開発者にとっても優れたリソースです。\n\n最新バージョンの Rust がインストールされていることを確認するには、`rustup update` を実行するか、[Rust をインストール](https://www.rust-lang.org/tools/install) します。\n\nRust をインストールした後、Cargo を使用して以下のコマンドを実行し、`trunk` をインストールします：\n\n```bash\ncargo install trunk\n```\n\nWASM のビルドターゲットも追加する必要があります。次のコマンドを実行します：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### プロジェクトの設定\n\nまず、新しい cargo プロジェクトを作成します：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nRust 環境が正しく設定されていることを確認するために、cargo ビルドツールを使用して初期プロジェクトを実行します。\nビルドプロセスの出力に続いて、期待される \"Hello, world!\" メッセージが表示されるはずです。\n\n```bash\ncargo run\n```\n\n## 最初の静的ページ\n\nこのシンプルなコマンドラインアプリケーションを基本的な Yew Web アプリケーションに変換するために、いくつかの変更が必要です。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\nアプリケーションを構築するだけの場合は、`csr` 特性のみが必要です。これにより、`Renderer` とクライアントサイドレンダリングに関連するすべてのコードが有効になります。\n\nライブラリを作成している場合は、この特性を有効にしないでください。クライアントサイドレンダリングロジックがサーバーサイドレンダリングパッケージに含まれてしまいます。\n\nテストやサンプルのために Renderer が必要な場合は、`dev-dependencies` で有効にするべきです。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nそれでは、プロジェクトのルートディレクトリに `index.html` を作成しましょう。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 開発サーバーの起動\n\n以下のコマンドを実行して、アプリケーションをビルドし、ローカルで提供します。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n`--open` オプションを削除して、`trunk serve` を実行した後にデフォルトのブラウザを開かないようにします。\n:::\n\nTrunk は、ソースコードファイルを変更するたびにアプリケーションをリアルタイムで再構築します。\nデフォルトでは、サーバーはアドレス '127.0.0.1' のポート '8080' でリッスンします => [http://localhost:8080](http://127.0.0.1:8080)。\nこの設定を変更するには、次のファイルを作成して必要に応じて編集します：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# ローカルネットワーク上のリッスンアドレス\naddress = \"127.0.0.1\"\n# 広域ネットワーク上のリッスンアドレス\n# address = \"0.0.0.0\"\n# リッスンするポート\nport = 8000\n```\n\nもし興味があれば、`trunk help` および `trunk help <subcommand>` を実行して、進行中のプロセスの詳細についてさらに学ぶことができます。\n\n### おめでとうございます\n\nこれで、Yew 開発環境を正常にセットアップし、最初の Yew Web アプリケーションを構築しました。\n\n## HTML の構築\n\nYew は Rust のプロシージャルマクロを利用しており、JSX（JavaScript の拡張で、JavaScript 内で HTML に似たコードを書くことができる）に似た構文を提供して、マークアップを作成します。\n\n### クラシック HTML への変換\n\n私たちのウェブサイトがどのように見えるかについての良いアイデアが既にあるので、単純にドラフトを `html!` と互換性のある表現に変換することができます。シンプルな HTML を書くことに慣れているなら、`html!` でマークアップを書くのに問題はないはずです。このマクロは HTML といくつかの違いがあることに注意してください：\n\n1. 式は中括弧（`{ }`）で囲む必要があります。\n2. ルートノードは1つだけでなければなりません。コンテナにラップせずに複数の要素を持ちたい場合は、空のタグ/フラグメント（`<> ... </>`）を使用できます。\n3. 要素は正しく閉じる必要があります。\n\nレイアウトを構築したいので、元の HTML は次のようになります：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nそれでは、この HTML を `html!` に変換しましょう。次のコードスニペットを `app` 関数の本体に入力（またはコピー/ペースト）して、関数が `html!` の値を返すようにします。\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\nブラウザページをリフレッシュすると、次の出力が表示されるはずです：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### マークアップ内でRustの構造を使用する\n\nRustでマークアップを書く大きな利点の1つは、マークアップ内でRustのすべての利点を享受できることです。\n今では、HTML内にビデオリストをハードコーディングするのではなく、それらを `Vec` の `Video` 構造体として定義します。\nデータを保持するために、`main.rs` または選択した任意のファイルにシンプルな `struct` を作成します。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n次に、この構造体のインスタンスを `app` 関数内で作成し、ハードコーディングされたデータの代わりにそれらを使用します：\n\n```rust\nuse website_test::tutorial::Video; // 自分のパスに置き換えてください\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\nそれらを表示するために、`Vec` を `Html` に変換する必要があります。これを実現するには、イテレータを作成し、それを `html!` にマッピングして `Html` として収集します：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\nリスト項目にキーを使用することで、Yew はリスト内のどの項目が変更されたかを追跡し、より高速な再レンダリングを実現できます。[リストには常にキーを使用することをお勧めします](/concepts/html/lists.mdx#keyed-lists)。\n::\n\n最後に、データから作成された `Html` を使用してハードコーディングされたビデオリストを置き換える必要があります：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## コンポーネント\n\nコンポーネントは Yew アプリケーションの構成要素です。コンポーネントを組み合わせることで（他のコンポーネントで構成されることもあります）、アプリケーションを構築します。再利用可能性を考慮してコンポーネントを構築し、それらを汎用的に保つことで、コードやロジックを繰り返すことなく、アプリケーションの複数の部分でそれらを使用できるようになります。\n\nこれまで使用してきた `app` 関数は `App` と呼ばれるコンポーネントであり、「関数コンポーネント」と呼ばれます。\n\n1. 構造体コンポーネント\n2. 関数コンポーネント\n\nこのチュートリアルでは、関数コンポーネントを使用します。\n\nでは、`App` コンポーネントをより小さなコンポーネントに分割しましょう。まず、ビデオリストを独自のコンポーネントに抽出します。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n`VideosList` 関数コンポーネントのパラメータに注意してください。関数コンポーネントは1つの引数しか受け取らず、その引数は \"props\"（\"properties\" の略）を定義します。Props は親コンポーネントから子コンポーネントにデータを渡すために使用されます。この場合、`VideosListProps` は props を定義する構造体です。\n\n:::important\nprops に使用される構造体は `Properties` を派生実装する必要があります。\n:::\n\n上記のコードをコンパイルするために、`Video` 構造体を次のように変更する必要があります：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n次に、`VideosList` コンポーネントを使用するように `App` コンポーネントを更新できます。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nブラウザウィンドウを確認することで、リストが期待通りにレンダリングされているかどうかを検証できます。リストのレンダリングロジックをそのコンポーネントに移動しました。これにより、`App` コンポーネントのソースコードが短くなり、読みやすく理解しやすくなりました。\n\n### アプリケーションをインタラクティブにする\n\nここでの最終目標は、選択したビデオを表示することです。そのためには、`VideosList` コンポーネントがビデオを選択したときに親コンポーネントに「通知」する必要があります。これは `Callback` を使用して行います。この概念は「ハンドラの伝播」と呼ばれます。props を変更して `on_click` コールバックを受け取るようにします：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n次に、選択したビデオをコールバックに渡すように `VideosList` コンポーネントを変更します。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n次に、`VideosList` の使用を変更してそのコールバックを渡す必要があります。しかし、その前に、新しいコンポーネント `VideoDetails` を作成し、ビデオがクリックされたときに表示されるようにします。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n次に、`App` コンポーネントを変更して、ビデオが選択されたときに `VideoDetails` コンポーネントを表示するようにします。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n今は `use_state` について心配する必要はありません。後でこの問題に戻ります。リストデータを `{ for details }` で抽出するテクニックに注目してください。\n`Option<_>` は `Iterator` を実装しているので、特殊な `{ for ... }` 構文を使用して `Iterator` が返す唯一の要素を順番に表示することができます。これは [`html!` マクロ](concepts/html/lists) によってサポートされています。\n\n### 状態の処理\n\n以前に使用した `use_state` を覚えていますか？それは \"フック\" と呼ばれる特殊な関数です。フックは関数コンポーネントのライフサイクルに \"フック\" して操作を実行するために使用されます。このフックや他のフックについては[こちら](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)で詳しく学ぶことができます。\n\n:::note\n構造体コンポーネントは異なる動作をします。これらについては[ドキュメント](advanced-topics/struct-components/introduction.mdx)を参照してください。\n:::\n\n## データの取得（外部 REST API の使用）\n\n実際のアプリケーションでは、データは通常ハードコーディングされているのではなく、API から取得されます。外部ソースからビデオリストを取得してみましょう。そのためには、以下のクレートを追加する必要があります：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  fetch 呼び出しを行うために使用します。\n- [`serde`](https://serde.rs) とその派生特性\n  JSON 応答をデシリアライズするために使用します。\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  Rust の Future を Promise として実行するために使用します。\n\n`Cargo.toml` ファイルの依存関係を更新しましょう：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n依存関係を選択する際には、それらが `wasm32` と互換性があることを確認してください！そうでない場合、アプリケーションを実行することはできません。\n:::\n\n`Deserialize` 特性を派生するように `Video` 構造体を更新します：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n最後のステップとして、ハードコーディングされたデータを使用するのではなく、fetch リクエストを行うように `App` コンポーネントを更新する必要があります。\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\nここでは `unwrap` を使用していますが、これはデモアプリケーションのためです。実際のアプリケーションでは、[適切なエラーハンドリング](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)を行うことをお勧めします。\n:::\n\nさて、ブラウザを確認して、すべてが期待通りに動作しているかを確認しましょう……CORS の問題がなければ。これを解決するために、プロキシサーバーが必要です。幸いなことに、trunk はこの機能を提供しています。\n\nこれらの行を更新します：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n次に、以下のコマンドを使用してサーバーを再起動します：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nページをリフレッシュすると、すべてが期待通りに動作するはずです。\n\n## まとめ\n\nおめでとうございます！外部 API からデータを取得し、ビデオリストを表示する Web アプリケーションを作成しました。\n\n## 次に\n\nこのアプリケーションは、完璧または有用になるまでにはまだ長い道のりがあります。このチュートリアルを完了した後、より高度なトピックを探求するための出発点として使用できます。\n\n### スタイル\n\n私たちのアプリケーションは非常に見栄えが悪いです。CSS やその他のスタイルがありません。残念ながら、Yew は組み込みのスタイルコンポーネントを提供していません。スタイルシートを追加する方法については、[Trunk のアセット](https://trunkrs.dev/assets/)を参照してください。\n\n### さらなる依存ライブラリ\n\n私たちのアプリケーションは、非常に少ない外部依存関係を使用しています。使用できる多くのクレートがあります。詳細については、[外部ライブラリ](/community/external-libs)を参照してください。\n\n### Yew についてもっと知る\n\n私たちの[公式ドキュメント](../getting-started/introduction.mdx)を読んでください。多くの概念についてより詳細に説明しています。Yew API についてもっと知りたい場合は、[API ドキュメント](https://docs.rs/yew)を参照してください。\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs/version-0.23.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.23\",\n    \"description\": \"The label for version 0.23\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Function Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Intro With Basic Web Technologies\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew mostly operates on the idea of keeping everything that a reusable piece of UI may need, in one place - rust files. But also seeks to stay close to the original look of the technology. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs-community/current.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-docs-router/current.json",
    "content": "{\n    \"version.label\": {\n        \"message\": \"Next\",\n        \"description\": \"The label for version current\"\n    }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-plugin-content-pages/index.mdx",
    "content": "---\ntitle: Introduction\nslug: /\n---\n\n## Yew とは?\n\n**Yew** は [WebAssembly](https://webassembly.org/) によってマルチスレッドな Web アプリのフロントエンドを作ることができる、モダンな [Rust](https://www.rust-lang.org/) のフレームワークです。\n\n- インタラクティブな UI を簡単に作ることができる、**コンポーネントベース** のフレームワークです. [React](https://reactjs.org/) や [Elm](https://elm-lang.org/) のようなフレームワークを使用したことがある開発者は Yew を違和感なく使うことができるでしょう。\n- DOM の API を呼び出すのを最小化し、開発者が Web ワーカーによって簡単に処理を軽量化できることで **素晴らしいパフォーマンス** を発揮します。\n- **JavaScript との互換性** をサポートし、開発者は npm のパッケージを活用し既存の JavaScript アプリと統合させることができます。\n\n### コミュニティに参加する 😊\n\n- [GitHub issues page](https://github.com/yewstack/yew/issues) でバグを報告したり機能について議論できます。\n- プルリクエストはぜひウェルカムです。ご協力いただけるなら [good first issues](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) をご確認ください。\n- 私たちの [Discord chat](https://discord.gg/VQck8X4) はとても活発で質問するのに良い場所です。\n\n### 始める準備はいいですか?\n\n以下のリンクをクリックして初めての Yew アプリの作り方を学び、コミュニティのプロジェクト例を見てみましょう。\n\n[始める](docs/getting-started/introduction)\n\n### まだ満足していませんか?\n\nこのプロジェクトは先進的な技術によって成り立っており、これからの基礎となるプロジェクトを作っていきたい開発者にとっては素晴らしいものです。\nここでは Yew のようなフレームワークがどうして Web 開発における未来となると考えられるかについての理由を述べていきます。\n\n#### 待って、どうして WebAssembly?\n\nWebAssembly _\\(Wasm\\)_ は Rust がコンパイル可能な軽量で低レベルな言語です。\nWebAssembly はブラウザでネイティブ並の速度で動き、JavaScript と互換性があり、そして全ての主要なブラウザでサポートされています。\nアプリで WebAssembly をどう使いこなすかについては [use cases](https://webassembly.org/docs/use-cases/) のリストをご確認ください。\n\n気をつけなければいけないこととして、Wasm は\\(まだ\\)Web アプリのパフォーマンスを改善する銀の弾丸ではありません。\n現時点では、DOM の API を WebAssembly から使うのはまだ JavaScript から直接呼ぶよりも遅いのです。\nこれは [WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) が解決しようとしている今のところの課題です。\n詳しい情報については Mozilla の提案が書いてある [excellent article](https://hacks.mozilla.org/2019/08/webassembly-interface-types/)\nをご確認ください。\n\n#### わかった、でもどうして Rust?\n\nRust は目まぐるしいほど高速に動作し、素晴らしい型と所有権モデルによって信頼性があります。\nRust には厳しい学習曲線がありますが、努力するだけの十分な価値があります。\nRust は Stack OverFlow による開発者調査で 5 年連続で最も愛されている言語に選ばれています:\n[2016](https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted),\n[2017](https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted),\n[2018](https://insights.stackoverflow.com/survey/2018#technology-_-most-loved-dreaded-and-wanted-languages),\n[2019](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages),\n[2020](https://insights.stackoverflow.com/survey/2020#most-loved-dreaded-and-wanted).\n\n同時に Rust は素晴らしい型システムと所有権モデルによって開発者がより安全なコードを書くようサポートしてくれます。\nJavaScript での追跡するのが難しいバグよ、さよなら！\n実際に Rust ではコードを走らせるまでもなくコンパイラによってバグのほとんどは捕捉されます。\nそして心配することなかれ、アプリを走らせてエラーになったとしてもブラウザのコンソールで Rust のコードを完全に追跡することができます。\n\n#### 代わりは?\n\n私たちは喜んで他のプロジェクトのアイデアを共有し、このワクワクする新たな技術のあらゆる可能性を実現できるよう皆が互いに助け合えると信じています。\nもし Yew がグッとこない場合は以下のプロジェクトがいいかもしれません。\n\n- [Percy](https://github.com/chinedufn/percy) - _\"Rust と WebAssembly で同一な Web アプリを作る組み立てツール\"_\n- [Seed](https://github.com/seed-rs/seed) - _\"Web アプリを作るための Rust フレームワーク\"_\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-theme-classic/footer.json",
    "content": "{\n  \"link.title.Support\": {\n    \"message\": \"Support\",\n    \"description\": \"The title of the footer links column with title=Support in the footer\"\n  },\n  \"link.title.Participate\": {\n    \"message\": \"Participate\",\n    \"description\": \"The title of the footer links column with title=Participate in the footer\"\n  },\n  \"link.title.More\": {\n    \"message\": \"More\",\n    \"description\": \"The title of the footer links column with title=More in the footer\"\n  },\n  \"link.item.label.Sponsor Project\": {\n    \"message\": \"Sponsor Project\",\n    \"description\": \"The label of footer link with label=Sponsor Project linking to https://opencollective.com/yew\"\n  },\n  \"link.item.label.GitHub\": {\n    \"message\": \"GitHub\",\n    \"description\": \"The label of footer link with label=GitHub linking to https://github.com/yewstack/yew\"\n  },\n  \"link.item.label.Discord\": {\n    \"message\": \"Discord\",\n    \"description\": \"The label of footer link with label=Discord linking to https://discord.gg/VQck8X4\"\n  },\n  \"link.item.label.Twitter\": {\n    \"message\": \"Twitter\",\n    \"description\": \"The label of footer link with label=Twitter linking to https://twitter.com/yewstack\"\n  },\n  \"link.item.label.Yew Awesome\": {\n    \"message\": \"Yew Awesome\",\n    \"description\": \"The label of footer link with label=Yew Awesome linking to https://github.com/jetli/awesome-yew\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/ja/docusaurus-theme-classic/navbar.json",
    "content": "{\n  \"title\": {\n    \"message\": \"Yew\",\n    \"description\": \"The title in the navbar\"\n  },\n  \"item.label.Docs\": {\n    \"message\": \"Docs\",\n    \"description\": \"Navbar item with label Docs\"\n  },\n  \"item.label.API\": {\n    \"message\": \"API\",\n    \"description\": \"Navbar item with label API\"\n  },\n  \"item.label.GitHub\": {\n    \"message\": \"GitHub\",\n    \"description\": \"Navbar item with label GitHub\"\n  },\n  \"item.label.Community\": {\n    \"message\": \"Community\",\n    \"description\": \"Navbar item with label Community\"\n  },\n  \"item.label.Tutorial\": {\n    \"message\": \"Tutorial\",\n    \"description\": \"Navbar item with label Tutorial\"\n  },\n  \"item.label.Blog\": {\n    \"message\": \"Blog\",\n    \"description\": \"Navbar item with label Blog\"\n  },\n  \"item.label.Playground\": {\n    \"message\": \"Playground\",\n    \"description\": \"Navbar item with label Playground\"\n  },\n  \"logo.alt\": {\n    \"message\": \"Yew Logo\",\n    \"description\": \"The alt text of navbar logo\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/code.json",
    "content": "{\n  \"theme.ErrorPageContent.title\": {\n    \"message\": \"This page crashed.\",\n    \"description\": \"The title of the fallback page when the page crashed\"\n  },\n  \"theme.ErrorPageContent.tryAgain\": {\n    \"message\": \"Try again\",\n    \"description\": \"The label of the button to try again rendering when the React error boundary captures an error\"\n  },\n  \"theme.NotFound.title\": {\n    \"message\": \"页面找不到啦\",\n    \"description\": \"The title of the 404 page\"\n  },\n  \"theme.NotFound.p1\": {\n    \"message\": \"We could not find what you were looking for.\",\n    \"description\": \"The first paragraph of the 404 page\"\n  },\n  \"theme.NotFound.p2\": {\n    \"message\": \"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.\",\n    \"description\": \"The 2nd paragraph of the 404 page\"\n  },\n  \"theme.AnnouncementBar.closeButtonAriaLabel\": {\n    \"message\": \"Close\",\n    \"description\": \"The ARIA label for close button of announcement bar\"\n  },\n  \"theme.BackToTopButton.buttonAriaLabel\": {\n    \"message\": \"Scroll back to top\",\n    \"description\": \"The ARIA label for the back to top button\"\n  },\n  \"theme.blog.archive.title\": {\n    \"message\": \"Archive\",\n    \"description\": \"The page & hero title of the blog archive page\"\n  },\n  \"theme.blog.archive.description\": {\n    \"message\": \"Archive\",\n    \"description\": \"The page & hero description of the blog archive page\"\n  },\n  \"theme.blog.paginator.navAriaLabel\": {\n    \"message\": \"Blog list page navigation\",\n    \"description\": \"The ARIA label for the blog pagination\"\n  },\n  \"theme.blog.paginator.newerEntries\": {\n    \"message\": \"Newer Entries\",\n    \"description\": \"The label used to navigate to the newer blog posts page (previous page)\"\n  },\n  \"theme.blog.paginator.olderEntries\": {\n    \"message\": \"Older Entries\",\n    \"description\": \"The label used to navigate to the older blog posts page (next page)\"\n  },\n  \"theme.blog.post.readingTime.plurals\": {\n    \"message\": \"{readingTime} min read\",\n    \"description\": \"Pluralized label for \\\"{readingTime} min read\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.blog.post.readMore\": {\n    \"message\": \"Read More\",\n    \"description\": \"The label used in blog post item excerpts to link to full blog posts\"\n  },\n  \"theme.blog.post.paginator.navAriaLabel\": {\n    \"message\": \"Blog post page navigation\",\n    \"description\": \"The ARIA label for the blog posts pagination\"\n  },\n  \"theme.blog.post.paginator.newerPost\": {\n    \"message\": \"Newer Post\",\n    \"description\": \"The blog post button label to navigate to the newer/previous post\"\n  },\n  \"theme.blog.post.paginator.olderPost\": {\n    \"message\": \"Older Post\",\n    \"description\": \"The blog post button label to navigate to the older/next post\"\n  },\n  \"theme.blog.sidebar.navAriaLabel\": {\n    \"message\": \"Blog recent posts navigation\",\n    \"description\": \"The ARIA label for recent posts in the blog sidebar\"\n  },\n  \"theme.blog.post.plurals\": {\n    \"message\": \"{count} posts\",\n    \"description\": \"Pluralized label for \\\"{count} posts\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.blog.tagTitle\": {\n    \"message\": \"{nPosts} tagged with \\\"{tagName}\\\"\",\n    \"description\": \"The title of the page for a blog tag\"\n  },\n  \"theme.tags.tagsPageLink\": {\n    \"message\": \"View All Tags\",\n    \"description\": \"The label of the link targeting the tag list page\"\n  },\n  \"theme.CodeBlock.copyButtonAriaLabel\": {\n    \"message\": \"Copy code to clipboard\",\n    \"description\": \"The ARIA label for copy code blocks button\"\n  },\n  \"theme.CodeBlock.copied\": {\n    \"message\": \"Copied\",\n    \"description\": \"The copied button label on code blocks\"\n  },\n  \"theme.CodeBlock.copy\": {\n    \"message\": \"Copy\",\n    \"description\": \"The copy button label on code blocks\"\n  },\n  \"theme.docs.sidebar.expandButtonTitle\": {\n    \"message\": \"Expand sidebar\",\n    \"description\": \"The ARIA label and title attribute for expand button of doc sidebar\"\n  },\n  \"theme.docs.sidebar.expandButtonAriaLabel\": {\n    \"message\": \"Expand sidebar\",\n    \"description\": \"The ARIA label and title attribute for expand button of doc sidebar\"\n  },\n  \"theme.docs.paginator.navAriaLabel\": {\n    \"message\": \"Docs pages navigation\",\n    \"description\": \"The ARIA label for the docs pagination\"\n  },\n  \"theme.docs.paginator.next\": {\n    \"message\": \"Next\",\n    \"description\": \"The label used to navigate to the next doc\"\n  },\n  \"theme.docs.paginator.previous\": {\n    \"message\": \"Previous\",\n    \"description\": \"The label used to navigate to the previous doc\"\n  },\n  \"theme.docs.sidebar.collapseButtonTitle\": {\n    \"message\": \"Collapse sidebar\",\n    \"description\": \"The title attribute for collapse button of doc sidebar\"\n  },\n  \"theme.docs.sidebar.collapseButtonAriaLabel\": {\n    \"message\": \"Collapse sidebar\",\n    \"description\": \"The title attribute for collapse button of doc sidebar\"\n  },\n  \"theme.docs.tagDocListPageTitle.nDocsTagged\": {\n    \"message\": \"One doc tagged|{count} docs tagged\",\n    \"description\": \"Pluralized label for \\\"{count} docs tagged\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.docs.tagDocListPageTitle\": {\n    \"message\": \"{nDocsTagged} with \\\"{tagName}\\\"\",\n    \"description\": \"The title of the page for a docs tag\"\n  },\n  \"theme.docs.versions.unreleasedVersionLabel\": {\n    \"message\": \"This is unreleased documentation for {siteTitle} {versionLabel} version.\",\n    \"description\": \"The label used to tell the user that he's browsing an unreleased doc version\"\n  },\n  \"theme.docs.versions.unmaintainedVersionLabel\": {\n    \"message\": \"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.\",\n    \"description\": \"The label used to tell the user that he's browsing an unmaintained doc version\"\n  },\n  \"theme.docs.versions.latestVersionSuggestionLabel\": {\n    \"message\": \"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).\",\n    \"description\": \"The label used to tell the user to check the latest version\"\n  },\n  \"theme.docs.versions.latestVersionLinkLabel\": {\n    \"message\": \"latest version\",\n    \"description\": \"The label used for the latest version suggestion link label\"\n  },\n  \"theme.common.editThisPage\": {\n    \"message\": \"Edit this page\",\n    \"description\": \"The link label to edit the current page\"\n  },\n  \"theme.common.headingLinkTitle\": {\n    \"message\": \"Direct link to heading\",\n    \"description\": \"Title for link to heading\"\n  },\n  \"theme.lastUpdated.atDate\": {\n    \"message\": \" on {date}\",\n    \"description\": \"The words used to describe on which date a page has been last updated\"\n  },\n  \"theme.lastUpdated.byUser\": {\n    \"message\": \" by {user}\",\n    \"description\": \"The words used to describe by who the page has been last updated\"\n  },\n  \"theme.lastUpdated.lastUpdatedAtBy\": {\n    \"message\": \"Last updated{atDate}{byUser}\",\n    \"description\": \"The sentence used to display when a page has been last updated, and by who\"\n  },\n  \"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel\": {\n    \"message\": \"← Back to main menu\",\n    \"description\": \"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)\"\n  },\n  \"theme.navbar.mobileVersionsDropdown.label\": {\n    \"message\": \"Versions\",\n    \"description\": \"The label for the navbar versions dropdown on mobile view\"\n  },\n  \"theme.common.skipToMainContent\": {\n    \"message\": \"Skip to main content\",\n    \"description\": \"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation\"\n  },\n  \"theme.tags.tagsListLabel\": {\n    \"message\": \"Tags:\",\n    \"description\": \"The label alongside a tag list\"\n  },\n  \"theme.TOCCollapsible.toggleButtonLabel\": {\n    \"message\": \"On this page\",\n    \"description\": \"The label used by the button on the collapsible TOC component\"\n  },\n  \"theme.blog.post.readMoreLabel\": {\n    \"message\": \"Read more about {title}\",\n    \"description\": \"The ARIA label for the link to full blog posts from excerpts\"\n  },\n  \"theme.colorToggle.ariaLabel\": {\n    \"message\": \"Switch between dark and light mode (currently {mode})\",\n    \"description\": \"The ARIA label for the color mode toggle\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.dark\": {\n    \"message\": \"dark mode\",\n    \"description\": \"The name for the dark color mode\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.light\": {\n    \"message\": \"light mode\",\n    \"description\": \"The name for the light color mode\"\n  },\n  \"theme.docs.versionBadge.label\": {\n    \"message\": \"Version: {versionLabel}\"\n  },\n  \"theme.navbar.mobileLanguageDropdown.label\": {\n    \"message\": \"Languages\",\n    \"description\": \"The label for the mobile language switcher dropdown\"\n  },\n  \"theme.docs.breadcrumbs.home\": {\n    \"message\": \"主页面\",\n    \"description\": \"The ARIA label for the home page in the breadcrumbs\"\n  },\n  \"theme.docs.breadcrumbs.navAriaLabel\": {\n    \"message\": \"页面路径\",\n    \"description\": \"The ARIA label for the breadcrumbs\"\n  },\n  \"theme.CodeBlock.wordWrapToggle\": {\n    \"message\": \"切换自动换行\",\n    \"description\": \"The title attribute for toggle word wrapping button of code block lines\"\n  },\n  \"theme.SearchBar.seeAll\": {\n    \"message\": \"查看全部结果\"\n  },\n  \"theme.SearchBar.label\": {\n    \"message\": \"搜索\",\n    \"description\": \"The ARIA label and placeholder for search button\"\n  },\n  \"theme.SearchPage.existingResultsTitle\": {\n    \"message\": \"“{query}” 的搜索结果\",\n    \"description\": \"The search page title for non-empty query\"\n  },\n  \"theme.SearchPage.emptyResultsTitle\": {\n    \"message\": \"搜索文档\",\n    \"description\": \"The search page title for empty query\"\n  },\n  \"theme.SearchPage.documentsFound.plurals\": {\n    \"message\": \"共找到 {count} 篇文档\",\n    \"description\": \"Pluralized label for \\\"{count} documents found\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.SearchPage.noResultsText\": {\n    \"message\": \"没有找到任何文档\",\n    \"description\": \"The paragraph for empty search result\"\n  },\n  \"theme.admonition.note\": {\n    \"message\": \"备注\",\n    \"description\": \"The default label used for the Note admonition (:::note)\"\n  },\n  \"theme.admonition.tip\": {\n    \"message\": \"提示\",\n    \"description\": \"The default label used for the Tip admonition (:::tip)\"\n  },\n  \"theme.admonition.danger\": {\n    \"message\": \"危险\",\n    \"description\": \"The default label used for the Danger admonition (:::danger)\"\n  },\n  \"theme.admonition.info\": {\n    \"message\": \"信息\",\n    \"description\": \"The default label used for the Info admonition (:::info)\"\n  },\n  \"theme.admonition.caution\": {\n    \"message\": \"警告\",\n    \"description\": \"The default label used for the Caution admonition (:::caution)\"\n  },\n  \"theme.tags.tagsPageTitle\": {\n    \"message\": \"标签\",\n    \"description\": \"The title of the tag list page\"\n  },\n  \"theme.NavBar.navAriaLabel\": {\n    \"message\": \"Main\",\n    \"description\": \"The ARIA label for the main navigation\"\n  },\n  \"theme.docs.sidebar.navAriaLabel\": {\n    \"message\": \"Docs sidebar\",\n    \"description\": \"The ARIA label for the sidebar navigation\"\n  },\n  \"theme.docs.sidebar.closeSidebarButtonAriaLabel\": {\n    \"message\": \"关闭导航栏\",\n    \"description\": \"The ARIA label for close button of mobile sidebar\"\n  },\n  \"theme.docs.sidebar.toggleSidebarButtonAriaLabel\": {\n    \"message\": \"切换导航栏\",\n    \"description\": \"The ARIA label for hamburger menu button of mobile navigation\"\n  },\n  \"theme.admonition.warning\": {\n    \"message\": \"注意\",\n    \"description\": \"The default label used for the Warning admonition (:::warning)\"\n  },\n  \"theme.DocSidebarItem.expandCategoryAriaLabel\": {\n    \"message\": \"展开侧边栏分类 '{label}'\",\n    \"description\": \"The ARIA label to expand the sidebar category\"\n  },\n  \"theme.DocSidebarItem.collapseCategoryAriaLabel\": {\n    \"message\": \"折叠侧边栏分类 '{label}'\",\n    \"description\": \"The ARIA label to collapse the sidebar category\"\n  },\n  \"theme.SearchPage.inputPlaceholder\": {\n    \"message\": \"在此输入搜索字词\",\n    \"description\": \"The placeholder for search page input\"\n  },\n  \"theme.SearchPage.inputLabel\": {\n    \"message\": \"搜索\",\n    \"description\": \"The ARIA label for search page input\"\n  },\n  \"theme.SearchPage.algoliaLabel\": {\n    \"message\": \"通过 Algolia 搜索\",\n    \"description\": \"The description label for Algolia mention\"\n  },\n  \"theme.SearchPage.fetchingNewResults\": {\n    \"message\": \"正在获取新的搜索结果...\",\n    \"description\": \"The paragraph for fetching new search results\"\n  },\n  \"theme.SearchModal.searchBox.resetButtonTitle\": {\n    \"message\": \"清除查询\",\n    \"description\": \"The label and ARIA label for search box reset button\"\n  },\n  \"theme.SearchModal.searchBox.cancelButtonText\": {\n    \"message\": \"取消\",\n    \"description\": \"The label and ARIA label for search box cancel button\"\n  },\n  \"theme.SearchModal.startScreen.recentSearchesTitle\": {\n    \"message\": \"最近搜索\",\n    \"description\": \"The title for recent searches\"\n  },\n  \"theme.SearchModal.startScreen.noRecentSearchesText\": {\n    \"message\": \"没有最近搜索\",\n    \"description\": \"The text when there are no recent searches\"\n  },\n  \"theme.SearchModal.startScreen.saveRecentSearchButtonTitle\": {\n    \"message\": \"保存这个搜索\",\n    \"description\": \"The title for save recent search button\"\n  },\n  \"theme.SearchModal.startScreen.removeRecentSearchButtonTitle\": {\n    \"message\": \"从历史记录中删除这个搜索\",\n    \"description\": \"The title for remove recent search button\"\n  },\n  \"theme.SearchModal.startScreen.favoriteSearchesTitle\": {\n    \"message\": \"收藏\",\n    \"description\": \"The title for favorite searches\"\n  },\n  \"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle\": {\n    \"message\": \"从收藏列表中删除这个搜索\",\n    \"description\": \"The title for remove favorite search button\"\n  },\n  \"theme.SearchModal.errorScreen.titleText\": {\n    \"message\": \"无法获取结果\",\n    \"description\": \"The title for error screen\"\n  },\n  \"theme.SearchModal.errorScreen.helpText\": {\n    \"message\": \"你可能需要检查网络连接。\",\n    \"description\": \"The help text for error screen\"\n  },\n  \"theme.SearchModal.footer.selectText\": {\n    \"message\": \"选中\",\n    \"description\": \"The select text for footer\"\n  },\n  \"theme.SearchModal.footer.selectKeyAriaLabel\": {\n    \"message\": \"Enter 键\",\n    \"description\": \"The ARIA label for select key in footer\"\n  },\n  \"theme.SearchModal.footer.navigateText\": {\n    \"message\": \"导航\",\n    \"description\": \"The navigate text for footer\"\n  },\n  \"theme.SearchModal.footer.navigateUpKeyAriaLabel\": {\n    \"message\": \"向上键\",\n    \"description\": \"The ARIA label for navigate up key in footer\"\n  },\n  \"theme.SearchModal.footer.navigateDownKeyAriaLabel\": {\n    \"message\": \"向下键\",\n    \"description\": \"The ARIA label for navigate down key in footer\"\n  },\n  \"theme.SearchModal.footer.closeText\": {\n    \"message\": \"关闭\",\n    \"description\": \"The close text for footer\"\n  },\n  \"theme.SearchModal.footer.closeKeyAriaLabel\": {\n    \"message\": \"Esc 键\",\n    \"description\": \"The ARIA label for close key in footer\"\n  },\n  \"theme.SearchModal.footer.searchByText\": {\n    \"message\": \"搜索提供\",\n    \"description\": \"The 'Powered by' text for footer\"\n  },\n  \"theme.SearchModal.noResultsScreen.noResultsText\": {\n    \"message\": \"没有结果：\",\n    \"description\": \"The text when there are no results\"\n  },\n  \"theme.SearchModal.noResultsScreen.suggestedQueryText\": {\n    \"message\": \"试试搜索\",\n    \"description\": \"The text for suggested query\"\n  },\n  \"theme.SearchModal.noResultsScreen.reportMissingResultsText\": {\n    \"message\": \"认为这个查询应该有结果？\",\n    \"description\": \"The text for reporting missing results\"\n  },\n  \"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText\": {\n    \"message\": \"请告知我们。\",\n    \"description\": \"The link text for reporting missing results\"\n  },\n  \"theme.SearchModal.placeholder\": {\n    \"message\": \"搜索文档\",\n    \"description\": \"The placeholder of the input of the DocSearch pop-up modal\"\n  },\n  \"theme.docs.DocCard.categoryDescription.plurals\": {\n    \"message\": \"{count} 个项目\",\n    \"description\": \"The default description for a category card in the generated index about how many items this category includes\"\n  },\n  \"theme.blog.author.pageTitle\": {\n    \"message\": \"{authorName} - {nPosts}\",\n    \"description\": \"The title of the page for a blog author\"\n  },\n  \"theme.blog.authorsList.pageTitle\": {\n    \"message\": \"Authors\",\n    \"description\": \"The title of the authors page\"\n  },\n  \"theme.blog.authorsList.viewAll\": {\n    \"message\": \"View All Authors\",\n    \"description\": \"The label of the link targeting the blog authors page\"\n  },\n  \"theme.contentVisibility.unlistedBanner.title\": {\n    \"message\": \"未列出页\",\n    \"description\": \"The unlisted content banner title\"\n  },\n  \"theme.contentVisibility.unlistedBanner.message\": {\n    \"message\": \"此页面未列出。搜索引擎不会对其索引，只有拥有直接链接的用户才能访问。\",\n    \"description\": \"The unlisted content banner message\"\n  },\n  \"theme.contentVisibility.draftBanner.title\": {\n    \"message\": \"Draft page\",\n    \"description\": \"The draft content banner title\"\n  },\n  \"theme.contentVisibility.draftBanner.message\": {\n    \"message\": \"This page is a draft. It will only be visible in dev and be excluded from the production build.\",\n    \"description\": \"The draft content banner message\"\n  },\n  \"theme.blog.author.noPosts\": {\n    \"message\": \"This author has not written any posts yet.\",\n    \"description\": \"The text for authors with 0 blog post\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.system\": {\n    \"message\": \"系统模式\",\n    \"description\": \"The name for the system color mode\"\n  },\n  \"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel\": {\n    \"message\": \"展开下拉菜单\",\n    \"description\": \"The ARIA label of the button to expand the mobile dropdown navbar item\"\n  },\n  \"theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel\": {\n    \"message\": \"收起下拉菜单\",\n    \"description\": \"The ARIA label of the button to collapse the mobile dropdown navbar item\"\n  },\n  \"theme.IconExternalLink.ariaLabel\": {\n    \"message\": \"(opens in new tab)\",\n    \"description\": \"The ARIA label for the external link icon\"\n  },\n  \"theme.SearchModal.searchBox.placeholderText\": {\n    \"message\": \"Search docs\",\n    \"description\": \"The placeholder text for the main search input field\"\n  },\n  \"theme.SearchModal.searchBox.placeholderTextAskAi\": {\n    \"message\": \"Ask another question...\",\n    \"description\": \"The placeholder text when in AI question mode\"\n  },\n  \"theme.SearchModal.searchBox.placeholderTextAskAiStreaming\": {\n    \"message\": \"Answering...\",\n    \"description\": \"The placeholder text for search box when AI is streaming an answer\"\n  },\n  \"theme.SearchModal.searchBox.enterKeyHint\": {\n    \"message\": \"search\",\n    \"description\": \"The hint for the search box enter key text\"\n  },\n  \"theme.SearchModal.searchBox.enterKeyHintAskAi\": {\n    \"message\": \"enter\",\n    \"description\": \"The hint for the Ask AI search box enter key text\"\n  },\n  \"theme.SearchModal.searchBox.searchInputLabel\": {\n    \"message\": \"Search\",\n    \"description\": \"The ARIA label for search input\"\n  },\n  \"theme.SearchModal.searchBox.backToKeywordSearchButtonText\": {\n    \"message\": \"Back to keyword search\",\n    \"description\": \"The text for back to keyword search button\"\n  },\n  \"theme.SearchModal.searchBox.backToKeywordSearchButtonAriaLabel\": {\n    \"message\": \"Back to keyword search\",\n    \"description\": \"The ARIA label for back to keyword search button\"\n  },\n  \"theme.SearchModal.startScreen.recentConversationsTitle\": {\n    \"message\": \"Recent conversations\",\n    \"description\": \"The title for recent conversations\"\n  },\n  \"theme.SearchModal.startScreen.removeRecentConversationButtonTitle\": {\n    \"message\": \"Remove this conversation from history\",\n    \"description\": \"The title for remove recent conversation button\"\n  },\n  \"theme.SearchModal.resultsScreen.askAiPlaceholder\": {\n    \"message\": \"Ask AI: \",\n    \"description\": \"The placeholder text for Ask AI input\"\n  },\n  \"theme.SearchModal.askAiScreen.disclaimerText\": {\n    \"message\": \"Answers are generated with AI which can make mistakes. Verify responses.\",\n    \"description\": \"The disclaimer text for AI answers\"\n  },\n  \"theme.SearchModal.askAiScreen.relatedSourcesText\": {\n    \"message\": \"Related sources\",\n    \"description\": \"The text for related sources\"\n  },\n  \"theme.SearchModal.askAiScreen.thinkingText\": {\n    \"message\": \"Thinking...\",\n    \"description\": \"The text when AI is thinking\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonText\": {\n    \"message\": \"Copy\",\n    \"description\": \"The text for copy button\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonCopiedText\": {\n    \"message\": \"Copied!\",\n    \"description\": \"The text for copy button when copied\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonTitle\": {\n    \"message\": \"Copy\",\n    \"description\": \"The title for copy button\"\n  },\n  \"theme.SearchModal.askAiScreen.likeButtonTitle\": {\n    \"message\": \"Like\",\n    \"description\": \"The title for like button\"\n  },\n  \"theme.SearchModal.askAiScreen.dislikeButtonTitle\": {\n    \"message\": \"Dislike\",\n    \"description\": \"The title for dislike button\"\n  },\n  \"theme.SearchModal.askAiScreen.thanksForFeedbackText\": {\n    \"message\": \"Thanks for your feedback!\",\n    \"description\": \"The text for thanks for feedback\"\n  },\n  \"theme.SearchModal.askAiScreen.preToolCallText\": {\n    \"message\": \"Searching...\",\n    \"description\": \"The text before tool call\"\n  },\n  \"theme.SearchModal.askAiScreen.duringToolCallText\": {\n    \"message\": \"Searching for \",\n    \"description\": \"The text during tool call\"\n  },\n  \"theme.SearchModal.askAiScreen.afterToolCallText\": {\n    \"message\": \"Searched for\",\n    \"description\": \"The text after tool call\"\n  },\n  \"theme.SearchModal.footer.submitQuestionText\": {\n    \"message\": \"Submit question\",\n    \"description\": \"The submit question text for footer\"\n  },\n  \"theme.SearchModal.footer.backToSearchText\": {\n    \"message\": \"Back to search\",\n    \"description\": \"The back to search text for footer\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-blog/options.json",
    "content": "{\n  \"title\": {\n    \"message\": \"Yew Blog\",\n    \"description\": \"The title for the blog used in SEO\"\n  },\n  \"description\": {\n    \"message\": \"Blog\",\n    \"description\": \"The description for the blog used in SEO\"\n  },\n  \"sidebar.title\": {\n    \"message\": \"Recent posts\",\n    \"description\": \"The label for the left sidebar\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/children.mdx",
    "content": "---\ntitle: '子组件'\n---\n\n:::caution\n\n检查和操作 `Children` 往往会导致应用程序中令人惊讶且难以解释的行为。这可能导致边缘情况，并且通常不会产生预期的结果。如果您尝试操作 `Children`，则应考虑其他方法。\n\nYew 支持将 `Html` 用作子组件属性的类型。如果您不需要 `Children` 或 `ChildrenRenderer`，则应使用 `Html` 作为子组件。它没有 `Children` 的缺点，并且性能开销较低。\n\n:::\n\n## 通用用法\n\n*大多数情况下，*当允许组件具有子组件时，您不关心组件具有的子组件的类型。在这种情况下，下面的示例就足够了。\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## 高级用法\n\n### 类型化子组件\n\n在您希望将一种类型的组件作为子组件传递给您的组件的情况下，您可以使用 `yew::html::ChildrenWithProps<T>`。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## 带有属性的嵌套子组件\n\n如果包含组件对其子组件进行了类型化，则可以访问和更改嵌套组件的属性。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 枚举类型的子组件\n\n当然，有时您可能需要将子组件限制为几种不同的组件。在这些情况下，您必须更深入地了解 Yew。\n\n这里使用 [`derive_more`](https://github.com/JelteF/derive_more) 来提供更好的人机工程学。如果您不想使用它，您可以为每个变体手动实现 `From`。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 现在，我们实现 `Into<Html>`，以便 yew 知道如何渲染 `Item`。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### 可选类型的子组件\n\n您还可以具有特定类型的单个可选子组件：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... 页面内容\n            </div>\n        }\n    }\n}\n\n// 页面组件可以选择是否附带侧边栏：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // 附带侧边栏的页面\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // 不附带侧边栏的页面\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## 进一步阅读\n\n- 有关此模式的真实示例，请查阅 yew-router 的源代码。有关更高级的示例，请查看 yew 存储库中的[相关示例清单](https://github.com/yewstack/yew/tree/master/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '工作原理'\ndescription: '关于框架的底层细节'\n---\n\n# 底层库的内部细节\n\n## `html!` 宏的内部\n\n`html!` macro 会将使用类似 HTML 的自定义语法编写的代码转换为有效的 Rust 代码。使用这个宏对于开发 Yew 应用程序并不是必需的，但是是推荐的。这个宏生成的代码使用了 Yew 的公共库 API，如果你愿意的话，可以直接使用。请注意，有些方法是有意未记录的，以避免意外的误用。随着 `yew-macro` 的每次更新，生成的代码将会更加高效，并且可以处理任何破坏性的更改，而不需要对 `html!` 语法进行很多（如果有的话）修改。\n\n由于 `html!` 宏允许您以声明式的风格编写代码，因此您的 UI 布局代码将与为页面生成的 HTML 非常相似。随着您的应用程序变得更加交互式，您的代码库变得更大，这种方式变得越来越有用。与手动编写所有操作 DOM 的代码相比，宏会为您处理好这一切。\n\n使用 `html!` 宏可能会让人感到非常神奇，但它并没有什么可隐藏的。如果您对它的工作原理感到好奇，可以尝试展开您程序中的 `html!` 宏调用。有一个有用的命令叫做 `cargo expand`，它允许您查看 Rust 宏的展开。`cargo expand` 并不是默认随 `cargo` 一起提供的，所以如果您还没有安装它，您需要使用 `cargo install cargo-expand` 来安装它。[Rust-Analyzer](https://rust-analyzer.github.io/) 也提供了一种[从 IDE 中获取宏输出的机制](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)。\n\n`html!` 宏的输出通常非常简洁！这是一个特性：机器生成的代码有时可能会与应用程序中的其他代码冲突。为了防止问题，`proc_macro` 遵循了“卫生”规则。一些例子包括：\n\n1. 为了确保正确引用 Yew 包，宏生成的代码中使用 `::yew::<module>`，而不是直接使用 `yew::<module>`。这也是为什么调用 `::alloc::vec::Vec::new()` 而不是直接调用 `Vec::new()`。\n2. 由于可能存在 trait 方法名称冲突，使用 `<Type as Trait>` 来确保我们使用的是正确的 trait 成员。\n\n## 什么是虚拟 DOM？\n\nDOM（\"文档对象模型\"）是由浏览器管理的 HTML 内容的表示。\"虚拟\" DOM 只是 DOM 的一个内存中的副本。管理虚拟 DOM 会导致更高的内存开销，但可以通过避免或延迟使用浏览器 API 来实现批处理和更快的读取。\n\n在内存中拥有 DOM 的副本对于促进使用声明式 UI 的库是有帮助的。与需要特定代码来描述如何根据用户事件修改 DOM 不同，库可以使用一种通用的方法来进行 DOM \"diffing\"。当 Yew 组件更新并希望更改其呈现方式时，Yew 库将构建虚拟 DOM 的第二个副本，并直接将其与镜像当前屏幕上的内容的虚拟 DOM 进行比较。两者之间的 \"diff\"（差异）可以分解为增量更新，并与浏览器 API 一起应用。一旦更新应用，旧的虚拟 DOM 副本将被丢弃，新的副本将被保存以供将来的差异检查。\n\n这种 \"diff\" 算法可以随着时间的推移进行优化，以提高复杂应用程序的性能。由于 Yew 应用程序是通过 WebAssembly 运行的，我们相信 Yew 在未来采用更复杂的算法方面具有竞争优势。\n\nYew 的虚拟 DOM 与浏览器 DOM 不完全一一对应。它还包括用于组织 DOM 元素的 \"列表\" 和 \"组件\"。列表可以简单地是元素的有序列表，但也可以更强大。通过为每个列表元素添加 \"key\" 注解，应用程序开发人员可以帮助 Yew 进行额外的优化，以确保在列表更改时，计算差异更新所需的工作量最小。同样，组件提供了自定义逻辑，指示是否需要重新渲染，以帮助提高性能。\n\n## Yew 调度器和组件范围的事件循环\n\n_贡献文档 - 深入解释 `yew::scheduler` 和 `yew::html::scope` 的工作原理_\n\n## 进一步阅读\n\n- [Rust 手册中关于宏的更多信息](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` 的更多信息](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` 的 API 文档](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/immutable.mdx",
    "content": "---\ntitle: '不可变类型'\ndescription: 'Yew 的不可变数据结构'\n---\n\n## 什么是不可变类型？\n\n这些类型是您可以实例化但永远不会更改值的类型。为了更新值，您必须实例化一个新值。\n\n## 为什么使用不可变类型？\n\n与 React 一样，属性是从祖先传播到子代的。这意味着属性在每个组件更新时必须存在。这就是为什么属性应该——理想情况下——很容易克隆。为了实现这一点，我们通常将事物包装在 `Rc` 中。\n\n不可变类型非常适合保存属性的值，因为它们可以在从组件传递到组件时以很低的成本克隆。\n\n## 常见的不可变类型\n\nYew 推荐使用来自 `implicit-clone` crate 的以下不可变类型：\n\n- `IString`（在 Yew 中别名为 `AttrValue`）- 用于字符串而不是 `String`\n- `IArray<T>` - 用于数组/向量而不是 `Vec<T>`\n- `IMap<K, V>` - 用于映射而不是 `HashMap<K, V>`\n\n这些类型是引用计数（`Rc`）或静态引用，使它们的克隆成本非常低。\n\n## 进一步阅读\n\n- [不可变示例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '优化 & 最佳实践'\nsidebar_label: Optimizations\ndescription: '让您的应用程序获得最佳性能'\n---\n\n## 使用智能指针\n\n**注意：如果您对本节中使用的某些术语感到困惑，Rust 手册中有一个有用的[关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)。**\n\n为了避免在重新渲染时克隆大量数据以创建 props，我们可以使用智能指针，只克隆对数据的引用而不是数据本身。如果您在 props 和子组件中传递与相关数据的引用而不是实际数据，您可以避免在需要修改数据的子组件中克隆任何数据，您可以使用 `Rc::make_mut` 来克隆并获得要更改的数据的可变引用。\n\n这在 `Component::changed` 中带来了更多好处，可以确定 prop 更改是否需要组件重新渲染。这是因为可以比较指针地址（即数据存储在机器内存中的位置）而不是数据的值；如果两个指针指向相同的数据，则它们指向的数据的值必须相同。请注意，反之可能不成立！即使两个指针地址不同，底层数据仍可能相同 - 在这种情况下，您应该比较底层数据。\n\n要进行此比较，您需要使用 `Rc::ptr_eq` 而不仅仅使用 `PartialEq`（在使用相等运算符 `==` 比较数据时自动使用）。Rust 文档有关于 `Rc::ptr_eq` 的[更多细节](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\n这种优化对于不实现 `Copy` 的数据类型最有用。如果您可以廉价地复制数据，则没有必要将其放在智能指针后面。对于可能是数据密集型的结构，如 `Vec`、`HashMap` 和 `String`，使用智能指针可能会带来性能改进。\n\n如果值从不被子组件更新，则此优化效果最佳，如果父组件很少更新，则效果更佳。这使得 `Rc<_>` 是在纯组件中包装属性值的一个不错的选择。\n\n但是，必须注意，除非您需要在子组件中自己克隆数据，否则这种优化不仅是无用的，而且还增加了不必要的引用计数成本。Yew 中的 props 已经是引用计数的，内部不会发生数据克隆。\n\n## 渲染函数\n\n出于代码可读性的原因，将 `html!` 的部分重复代码迁移到专门分割出来的函数中通常是有意义的。这不仅使您的代码更易读，减少了代码缩进，而且还鼓励良好的设计模式——特别是围绕构建可组合应用程序，这些函数可以在多个地方调用，从而减少代码量。\n\n## 纯组件\n\n纯组件是不会改变其状态的组件，只显示内容并将消息传播到普通的可变组件。它们与视图函数的不同之处在于，它们可以在 `html!` 宏中使用组件语法（`<SomePureComponent />`）而不是表达式语法（`{some_view_function()}`），并且根据其实现，它们可以被记忆化（这意味着一旦调用函数，其值就会被“保存”，因此如果多次使用相同的参数调用它，则不必重新计算其值，只需从第一个函数调用返回保存的值）- 防止相同的 props 重新渲染。Yew 在内部比较 props，因此仅在 props 更改时重新渲染 UI。\n\n## 使用工作区减少编译时间\n\nYew 的最大缺点是编译所需的时间很长。编译项目所需的时间似乎与传递给 `html!` 宏的代码数量有关。对于较小的项目，这似乎不是什么问题，但对于较大的应用程序，将代码拆分到多个 crate 中以最小化编译器为应用程序所做的工作量是有意义的。\n\n一种可能的方法是使您的主 crate 处理路由/页面选择，然后为每个页面创建一个不同的 crate，其中每个页面可以是不同的组件或只是生成 `Html` 的大函数。存储在包含应用程序不同部分的 crate 之间的代码可以存储在项目依赖的单独 crate 中。在最理想的情况下，您从在每次编译时重新构建所有代码到仅重新构建主 crate 和一个页面 crate。在最坏的情况下，如果您在“common” crate 中编辑了某些内容，您将回到起点：编译依赖于该常用共享 crate 的所有代码，这可能是其他所有内容。\n\n如果您的主 crate 太重，或者您想快速迭代一个深度嵌套的页面（例如。在另一个页面上渲染的页面），您可以使用示例 crate 创建主页面的简化实现，并额外渲染您正在处理的组件。\n\n## 减小二进制文件大小\n\n- 优化 Rust 代码\n- `cargo.toml`（定义发布配置文件）\n- 使用 `wasm-opt` 优化 wasm 代码\n\n**注意：有关减小二进制文件大小的更多信息，请参阅[Rust Wasm 手册](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)。**\n\n### Cargo.toml\n\n可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用设置来配置发布构建为更小。\n\n```toml, title=Cargo.toml\n[profile.release]\n# 让二进制文件尺寸更小些\npanic = 'abort'\n# 优化整个代码库（优化更好，但构建速度也会更慢）\ncodegen-units = 1\n# 优化尺寸（更激进的做法）\nopt-level = 'z'\n# 优化尺寸\n# opt-level = 's'\n# 使用程序整体分析时进行链接时优化\nlto = true\n```\n\n### 开发版 Cargo 配置\n\n您还可以从 Rust 和 cargo 的实验性开发版功能中获得额外的好处。要使用 `trunk` 的开发版工具链，请设置 `RUSTUP_TOOLCHAIN=\"nightly\"` 环境变量。然后，您可以在 `.cargo/config.toml` 中配置不稳定的 rustc 功能。请参考[不稳定功能]的文档，特别是关于[`build-std`]和[`build-std-features`]的部分，以了解配置。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# 需要 rust-src 组件。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不稳定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n开发版 Rust 编译器可能包含错误，例如[这个例子](https://github.com/yewstack/yew/issues/2696)，需要偶尔关注和调整。请谨慎使用这些实验性选项。\n:::\n\n### wasm-opt\n\n此外，可以优化 `wasm` 代码的大小。\n\nRust Wasm 手册中有关于减小 Wasm 二进制文件大小的部分：[缩小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用 `wasm-pack`，默认情况下会优化发布构建中的 `wasm` 代码\n- 直接在 `wasm` 文件上使用 `wasm-opt`\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 在 yew/examples/ 中 'minimal' 示例的构建大小\n\n注意：`wasm-pack` 结合了 Rust 和 Wasm 代码的优化。在此示例中，`wasm-bindgen` 未经任何 Rust 大小优化。\n\n| 工具链                      | 大小  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## 进一步阅读\n\n- [Rust 手册中关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm 手册中关于减小二进制文件大小的信息](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust 配置文件的文档](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen 项目](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/portals.mdx",
    "content": "---\ntitle: '传送门 (Portals)'\ndescription: '将内容渲染到 DOM 树外的节点'\n---\n\n## 什么是 Portal？\n\n传送门 (Portal) 提供了一种将子元素渲染到父组件的 DOM 层次结构之外的 DOM 节点的方法。`yew::create_portal(child, host)` 返回一个 `Html` 值，它将 `child` 渲染为 `host` 元素的子元素，而不是在其父组件的层次结构下。\n\n## 用法\n\n传送门的典型用途包括模态对话框和悬停卡片，以及更多技术应用，例如控制元素的 [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) 的内容，将样式表附加到周围文档的 `<head>` 中，以及在 `<svg>` 的中央 `<defs>` 元素中收集引用的元素。\n\n请注意，`yew::create_portal` 是一个低级构建块。库应该使用它来实现更高级的 API，然后应用程序可以使用这些 API。例如，这里是一个简单的模态对话框，它将其 `children` 渲染到 `yew` 之外的一个元素中，该元素由 `id=\"modal_host\"` 标识。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## 事件处理\n\n传送门内部元素上发出的事件遵循虚拟 DOM 冒泡。也就是说，如果传送门被渲染为元素的子元素，那么该元素上的事件监听器将捕获从传送门内部分发出的事件，即使传送门将其内容渲染在实际 DOM 中的不相关位置。\n\n这使开发人员无需关心他们使用的组件是使用传送门实现的还是没有使用传送门实现的。无论如何，其子元素上触发的事件都会冒泡。\n\n已知问题是，从传送门到 **关闭** 的 shadow root 的事件将被分发两次，一次针对 shadow root 内部的元素，一次针对宿主元素本身。请记住，**打开** 的 shadow root 可以正常工作。如果这影响到您，请随时提交一个错误报告。\n\n## 进一步阅读\n\n- [传送门示例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: '服务端渲染'\ndescription: '在服务端渲染 Yew 组件。'\n---\n\n# 服务端渲染 (Server-Side Rendering)\n\n默认情况下，Yew 组件在客户端渲染。当用户访问一个网站时，服务器会发送一个骨架 HTML 文件，不包含任何实际内容，以及一个 WebAssembly 包给浏览器。所有内容都由 WebAssembly 包在客户端渲染。这被称为客户端渲染。\n\n这种方法对于大多数网站来说都是有效的，但有一些注意事项：\n\n1. 用户在整个 WebAssembly 包下载并完成初始渲染之前将看不到任何内容。这可能会导致在缓慢的网络上用户体验不佳。\n2. 一些搜索引擎不支持动态渲染的网页内容，而那些支持的搜索引擎通常会将动态网站排名较低。\n\n为了解决这些问题，我们可以在服务端渲染我们的网站。\n\n## 工作原理\n\nYew 提供了一个 `ServerRenderer` 来在服务端渲染页面。\n\n要在服务端渲染 Yew 组件，您可以使用 `ServerRenderer::<App>::new()` 创建一个渲染器，并调用 `renderer.render().await` 将 `<App />` 渲染为一个 `String`。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// 我们在使用 `flavor = \"current_thread\"` 以保证这个示例可以在 CI 中的 WASM 环境运行,\n// 如果你希望使用多线程的话，可以使用默认的 `#[tokio::main]` 宏\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // 打印: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## 组件生命周期\n\n与客户端渲染不同，组件的生命周期在服务端渲染时会有所不同。\n\n在组件成功第一次渲染为 `Html` 之前，除了 `use_effect` (和 `use_effect_with`) 之外的所有钩子都会正常工作。\n\n:::caution 浏览器接口不可用！\n\n浏览器相关的接口，如 `web_sys`，在组件在服务端渲染时是不可用的。如果您尝试使用它们，您的应用程序将会崩溃。您应该将需要这部分逻辑隔离在 `use_effect` 或 `use_effect_with` 中，因为在服务端渲染时它们无法也不应当执行。\n\n:::\n\n:::danger 结构化组件\n\n尽管可以在服务端渲染时使用结构化组件，但是在客户端安全逻辑（如函数组件的 `use_effect` 钩子）和生命周期事件之间没有明确的边界，并且生命周期事件的调用顺序与客户端不同。\n\n此外，结构化组件将继续接受消息，直到所有子组件都被渲染并调用了 `destroy` 方法。开发人员需要确保不会将可能传递给组件的消息链接到调用浏览器接口的逻辑。\n\n在设计支持服务端渲染的应用程序时，请尽量使用函数组件，除非您有充分的理由不这样做。\n\n:::\n\n## 服务端渲染期间的数据获取\n\n数据获取是服务端渲染和水合（hydration）期间的难点之一。\n\n传统做法中，当一个组件渲染时，它会立即可用（输出一个虚拟 DOM 以进行渲染）。当组件不需要获取任何数据时，这种方式是有效的。但是如果组件在渲染时想要获取一些数据会发生什么呢？\n\n过去，Yew 没有机制来检测组件是否仍在获取数据。数据获取客户端负责实现一个解决方案，以检测在初始渲染期间请求了什么，并在请求完成后触发第二次渲染。服务器会重复这个过程，直到在返回响应之前没有在渲染期间添加更多的挂起请求。\n\n这不仅浪费了 CPU 资源，因为重复渲染组件，而且数据客户端还需要提供一种方法，在水合过程中使在服务端获取的数据可用，以确保初始渲染返回的虚拟 DOM 与服务端渲染的 DOM 树一致，这可能很难实现。\n\nYew 采用了一种不同的方法，通过 `<Suspense />` 来解决这个问题。\n\n`<Suspense />` 是一个特殊的组件，当在客户端使用时，它提供了一种在组件获取数据（挂起）时显示一个回退 UI 的方法，并在数据获取完成后恢复到正常 UI。\n\n当应用程序在服务端渲染时，Yew 会等待组件不再挂起，然后将其序列化到字符串缓冲区中。\n\n在水合过程中，`<Suspense />` 组件中的元素保持未水合状态，直到所有子组件不再挂起。\n\n通过这种方法，开发人员可以轻松构建一个准备好进行服务端渲染的、与客户端无关的应用程序，并进行数据获取。\n\n## 渲染 `<head>` 标签\n\nSSR 中的一个常见需求是渲染动态 `<head>` 内容（例如 `<title>`、`<meta>`），使爬虫和社交预览在首次加载时能看到正确的元数据。\n\n`ServerRenderer` 只渲染组件树（通常对应文档的 body 部分），无法访问 `<head>`。因此，head 标签必须**在服务端、Yew 之外**生成，并在发送给客户端之前拼接到 HTML 模板中。\n\n[`ssr_router` 示例](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) 演示了这一模式：服务端从请求 URL 识别路由，生成适当的 `<title>` 和 `<meta>` 标签，并将它们注入到 Trunk 生成的 `index.html` 的 `</head>` 之前。\n\n:::info\n\n如需完全兼容 SSR 的第三方解决方案，请使用 [Bounce 的 `<Helmet/>` 组件](https://docs.rs/bounce/latest/bounce/helmet/index.html)。\n\n:::\n\n## SSR 水合（SSR Hydration）\n\n水合是将 Yew 应用程序连接到服务端生成的 HTML 文件的过程。默认情况下，`ServerRender` 打印可水合的 HTML 字符串，其中包含额外的信息以便于水合。当调用 `Renderer::hydrate` 方法时，Yew 不会从头开始渲染，而是将应用程序生成的虚拟 DOM 与服务器渲染器生成的 HTML 字符串进行协调。\n\n:::caution\n\n要成功对由 `ServerRenderer` 创建的 HTML 标记进行水合，客户端必须生成一个虚拟 DOM 布局，它与用于 SSR 的布局完全匹配，包括不包含任何元素的组件。如果您有任何只在一个实现中有用的组件，您可能希望使用 `PhantomComponent` 来填充额外组件的位置。\n:::\n\n:::warning\n\n只有在浏览器初始渲染 SSR 输出（静态 HTML）后，真实 DOM 与预期 DOM 匹配时，水合才能成功。如果您的 HTML 不符合规范，水合可能会失败。浏览器可能会更改不正确的 HTML 的 DOM 结构，导致实际 DOM 与预期 DOM 不同。例如，[如果您有一个没有 `<tbody>` 的 `<table>`，浏览器可能会向 DOM 添加一个 `<tbody>`](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## 水合期间的组件生命周期\n\n在水合期间，组件在创建后安排了 2 次连续的渲染。任何效果都是在第二次渲染完成后调用的。确保您的组件的渲染函数没有副作用是很重要的。它不应该改变任何状态或触发额外的渲染。如果您的组件当前改变状态或触发额外的渲染，请将它们移动到 `use_effect` 钩子中。\n\n在水合过程中，可以使用结构化组件进行服务端渲染，视图函数将在渲染函数之前被调用多次。直到调用渲染函数之前，DOM 被认为是未连接的，您应该防止在调用 `rendered()` 方法之前访问渲染节点。\n\n## 示例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // 对 body 元素下的所有内容进行水合，并移除尾部元素（如果有）。\n    renderer.hydrate();\n}\n```\n\n示例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n示例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## 单线程模式\n\nYew 支持以单线程进行服务端渲染，通过 `yew::LocalServerRenderer`。这种模式适用于像 WASI 这样的单线程环境。\n\n```rust\n// 使用 `wasm32-wasip1` 或 `wasm32-wasip2` 目标构建。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n示例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n如果您使用 `wasm32-unknown-unknown` 目标构建 SSR 应用程序，您可以使用 `not_browser_env` 功能标志来禁用 Yew 内部对特定于浏览器的 API 的访问。这在像 Cloudflare Worker 这样的无服务器平台上非常有用。\n:::\n\n:::caution\n\n服务端渲染目前是实验性的。如果您发现了一个 bug，[请在 GitHub 反馈](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回调函数 (Callbacks)'\n---\n\n## 回调函数 (Callbacks)\n\n回调函数是用于在 Yew 中与服务、代理和父组件进行通信的。在内部，它们的类型只是 `Fn` 包装在 `Rc` 中，以允许它们被克隆。\n\n它们有一个 `emit` 函数，该函数以其 `<IN>` 类型作为参数，并将其转换为其目标期望的消息。如果父组件中的回调函数作为 props 提供给子组件，子组件可以在其 `update` 生命周期钩子中调用回调函数的 `emit` 函数，以将消息发送回其父组件。在 `html!` 宏中作为 props 提供的闭包或函数会自动转换为回调函数。\n\n一个简单的回调函数的使用可能如下所示：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\n这个函数传递给 `callback` 必须始终带有一个参数。例如，`onclick` 处理程序需要一个接受 `MouseEvent` 类型参数的函数。然后处理程序可以决定应该发送什么类型的消息给组件。这个消息无条件地被安排在下一个更新循环中。\n\n如果你需要一个回调函数，它可能不需要引起更新，请使用 `batch_callback`。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 相关示例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高阶组件'\n---\n\n在一些情况下，结构组件不直接支持某些功能（例如 Suspense），或者使用某些功能需要大量的样板代码（例如 Context）。\n\n在这些情况下，建议创建高阶组件的函数组件。\n\n## 高阶组件定义\n\n高阶组件是不添加任何新 HTML 的组件，只是包装其他组件以提供额外功能。\n\n### 示例\n\n对 Context (上下文) 挂钩并将其传递给结构组件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '简介'\ndescription: 'Yew 中的组件'\n---\n\n## 什么是组件？\n\n组件是 Yew 的构建块。它们管理内部状态并可以将元素渲染到 DOM 中。通过为类型实现 `Component` trait 来创建组件。\n\n## 编写组件标记\n\nYew 使用虚拟 DOM 将元素渲染到 DOM 中。虚拟 DOM 树可以通过使用 `html!` 宏来构建。`html!` 使用的语法类似于 HTML，但并不相同。规则也更严格。它还提供了诸如条件渲染和使用迭代器渲染列表等超能力。\n\n:::info\n[了解更多关于 `html!` 宏，如何使用它以及它的语法](concepts/html/introduction.mdx)\n:::\n\n## 将数据传递给组件\n\nYew 组件使用 _props_ 在父组件和子组件之间通信。父组件可以将任何数据作为 props 传递给其子组件。Props 类似于 HTML 属性，但可以将任何 Rust 类型作为 props 传递。\n\n:::info\n[了解更多关于 props 的内容](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n对于除了父/子通信之外的其他通信，请使用 [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命周期'\ndescription: '组件及其生命周期钩子'\n---\n\n`Component` trait 有许多方法需要实现；Yew 会在组件的生命周期的不同阶段调用这些方法。\n\n## 生命周期\n\n:::important 改进文档\n`为文档做贡献：` [添加定制生命周期的组件示例](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命周期方法\n\n### Create\n\n当组件被创建时，它会从其父组件接收属性，并存储在传递给 `create` 方法的 `Context<Self>` 中。这些属性可以用来初始化组件的状态，而 \"link\" 可以用来注册回调或向组件发送消息。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体实现\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法允许您描述组件应该如何呈现到 DOM 中。使用 Rust 函数编写类似 HTML 的代码可能会变得非常混乱，因此 Yew 提供了一个名为 `html!` 的宏，用于声明 HTML 和 SVG 节点（以及将属性和事件监听器附加到它们）以及一种方便的方法来渲染子组件。这个宏在某种程度上类似于 React 的 JSX（除了编程语言的差异）。一个不同之处是 Yew 提供了一种类似 Svelte 的属性的简写语法，其中您可以只写 `{onclick}`，而不用写 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n就使用上的说明，请查看 [html! 指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 组件生命周期方法在 `view` 被调用并且 Yew 已经将结果渲染到 DOM 中后调用，但在浏览器刷新页面之前。当您想要执行只能在组件渲染元素后完成的操作时，此方法非常有用。还有一个名为 `first_render` 的参数，可以用来确定此函数是在第一次渲染时调用，还是在后续渲染时调用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n请注意，此生命周期方法不需要实现，并且默认情况下不会执行任何操作。\n:::\n\n### Update\n\n与组件的通信主要通过消息进行，这些消息由 `update` 生命周期方法处理。这允许组件根据消息更新自身，并确定是否需要重新渲染自身。消息可以由事件监听器、子组件、Agents、Services 或 Futures 发送。\n\n下面是 `update` 的一个实现示例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 重新渲染\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体实现\n        }\n    }\n}\n```\n\n### Changed\n\n组件可能会被其父组件重新渲染。当这种情况发生时，它们可能会接收新的属性并需要重新渲染。这种设计通过仅更改属性的值来促进父子组件之间的通信。当属性更改时，有一个默认实现会重新渲染组件。\n\n### Destroy\n\n组件从 DOM 中卸载后，Yew 会调用 `destroy` 生命周期方法；如果您需要在组件被销毁之前执行清理操作，这是必要的。此方法是可选的，默认情况下不执行任何操作。\n\n### 无限循环\n\n无限循环在 Yew 的生命周期方法中是可能的，但只有在尝试在每次渲染后更新相同的组件时，当该更新还要求重新渲染组件时才会发生。\n\n下面是一个简单的示例：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // 我们总是请求在任何消息上重新渲染\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // 无论渲染什么都不重要\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // 请求使用此新消息更新组件\n        ctx.link().send_message(());\n    }\n}\n```\n\n让我们看看这里发生了什么：\n\n1. 使用 `create` 函数创建组件。\n2. 调用 `view` 方法，以便 Yew 知道要渲染到浏览器 DOM 中的内容。\n3. 调用 `rendered` 方法，使用 `Context` 链接安排更新消息。\n4. Yew 完成后渲染阶段。\n5. Yew 检查已安排的事件，并看到更新消息队列不为空，因此处理消息。\n6. 调用 `update` 方法，返回 `true` 表示发生了变化，组件需要重新渲染。\n7. 跳回到第 2 步。\n\n您仍然可以在 `rendered` 方法中安排更新，这通常是有用的，但是在这样做时，请考虑您的组件将如何终止此循环。\n\n## 关联类型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 类型用于在事件发生后向组件发送消息；例如，您可能希望在用户单击按钮或向下滚动页面时执行某些操作。因为组件通常需要响应多个事件，所以 `Message` 类型通常是一个枚举，其中每个变体都是要处理的事件。\n\n在组织代码库时，将 `Message` 类型的定义包含在定义组件的同一模块中是明智的。您可能会发现采用一致的命名约定来命名消息类型很有帮助。一个选项（尽管不是唯一的选项）是将类型命名为 `ComponentNameMsg`，例如，如果您的组件名为 `Homepage`，则可以将类型命名为 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示从其父组件传递给组件的信息。此类型必须实现 `Properties` trait（通常通过派生它）并可以指定某些属性是必需的还是可选的。在创建和更新组件时使用此类型。在组件的模块中创建一个名为 `Props` 的结构体，并将其用作组件的 `Properties` 类型是一种常见做法。通常将 \"properties\" 缩写为 \"props\"。由于 props 是从父组件传递下来的，因此应用程序的根组件通常具有 `Properties` 类型为 `()`。如果要为根组件指定属性，请使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多关于属性的信息](./properties)\n:::\n\n## 生命周期上下文\n\n所有组件生命周期方法都接受一个上下文对象。此对象提供了对组件作用域的引用，允许向组件发送消息并传递给组件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '属性 (Props)'\ndescription: '父子组件通信'\n---\n\n属性 (Properties) 使子组件和父组件之间能够进行通信。每个组件都有一个关联的属性类型，用于描述从父组件传递下来的内容。理论上，这可以是任何实现了 `Properties` 特性的类型，但实际上，它应该是一个结构体，其中每个字段代表一个属性。\n\n## 派生宏\n\n无需自己实现 `Properties` 特性，我们可以用 `#[derive(Properties)]` 来自动生成实现。派生 `Properties` 的类型也必须实现 `PartialEq`。\n\n### 字段属性\n\n在派生 `Properties` 时，默认情况下所有字段都是必需的。以下属性允许您为属性提供初始值，除非它们被设置为另一个值。\n\n:::tip\n属性不会在 Rustdoc 生成的文档中显示。您的属性的文档字符串应该说明一个属性是否是可选的，以及它是否有一个特殊的默认值。\n:::\n\n#### `#[prop_or_default]`\n\n使用字段类型的默认值使用 `Default` 特性来初始化属性值。\n\n#### `#[prop_or(value)]`\n\n使用 `value` 来初始化属性值。`value` 可以是返回字段类型的任何表达式。例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。\n\n#### `#[prop_or_else(function)]`\n\n调用 `function` 来初始化属性值。`function` 应该具有签名 `FnMut() -> T`，其中 `T` 是字段类型。\n\n## `PartialEq`\n\n`Properties` 需要实现 `PartialEq`。这样，Yew 才能比较它们，以便在它们发生变化时调用 `changed` 方法。\n\n## 使用 Properties 的性能开销\n\n内部属性是基于引用计数的指针存储的。这意味着只有一个指针被传递到组件树中的属性，以避免克隆整个属性所带来的昂贵性能开销。\n\n:::tip\n使用 `AttrValue`，这是我们提供的自定义属性值类型，这样就可以不用 String 或其他类似的需要克隆的类型。\n:::\n\n## 示例\n\n```rust\nuse yew::Properties;\n/// 从 virtual_dom 中导入 AttrValue\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标\n    href: AttrValue,\n    /// 还要注意我们使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 链接的颜色，默认为 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值为 None，则视图函数不会指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 当视图函数没有指定活动时，默认为 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n该宏使用与结构体表达式相同的语法，只是您不能使用属性或基本表达式 (`Foo { ..base }`)。类型路径可以直接指向属性 (`path::to::Props`)，也可以指向组件的关联属性 (`MyComp::Properties`)。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标\n    href: AttrValue,\n    /// 还要注意我们使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 链接的颜色，默认为 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值为 None，则视图函数不会指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 当视图函数没有指定活动时，默认为 true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// 注意此函数接收 href 和 text 作为 String\n    /// 我们可以使用 `AttrValue::from` 将其转换为 `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '引用 (Refs)'\ndescription: '实现越界 DOM 访问'\n---\n\n`ref` 关键字可以在任何 HTML 元素或组件中使用，以获取附加到该元素的 DOM `Element`。这可以用于在 `view` 生命周期方法之外对 DOM 进行更改。\n\n这对于获取 canvas 元素或滚动到页面的不同部分很有用。例如，在组件的 `rendered` 方法中使用 `NodeRef` 允许您在从 `view` 渲染后对 canvas 元素进行绘制调用。\n\n语法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 相关示例\n\n- [节点引用](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: '作用域'\ndescription: '组件的作用域'\n---\n\n## 组件的 `Scope<_>` 接口\n\n`Scope` 是通过消息创建回调并更新自身的机制。我们通过在传递给组件的上下文对象上调用 `link()` 来获得对它的引用。\n\n### `send_message`\n\n这个函数可以向组件发送消息。消息由 `update` 方法处理，该方法确定组件是否应重新渲染。\n\n### `send_message_batch`\n\n这个函数可以同时向组件发送多个消息。这类似于 `send_message`，但是如果任何消息导致 `update` 方法返回 `true`，则组件将在处理完批处理中的所有消息后重新渲染。\n\n如果给定的参数向量为空，则此函数不执行任何操作。\n\n### `callback`\n\n创建一个回调，当执行时将向组件发送消息。在内部，它将使用提供的闭包返回的消息调用 `send_message`。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // 创建一个接受一些文本并将其作为 `Msg::Text` 消息变体发送到组件的回调。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上一行是多余的冗长，为了更清晰，可以简化为这样：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // 将 `Msg::Text(\"Hello World!\")` 发送到组件。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // 在这里放置 HTML\n        }\n    }\n}\n```\n\n### `batch_callback`\n\n创建一个回调，当执行时将向组件发送一批消息。与 `callback` 的区别在于，传递给此方法的闭包不必返回消息。相反，闭包可以返回 `Vec<Msg>` 或 `Option<Msg>`，其中 `Msg` 是组件的消息类型。\n\n`Vec<Msg>` 被视为一批消息，并在内部使用 `send_message_batch`。\n\n`Option<Msg>` 在值为 `Some` 时调用 `send_message`。如果值为 `None`，则不执行任何操作。这可以用于根据情况，不需要更新的情况。\n\n这是通过使用仅为这些类型实现的 `SendAsMessage` trait 实现的。您可以为自己的类型实现 `SendAsMessage`，这样可以在 `batch_callback` 中使用它们。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/agents.mdx",
    "content": "---\ntitle: '代理 (Agents)'\ndescription: \"Yew's 的代理系统\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n代理 (Agents) 是一种将任务卸载到 Web Workers 的方式。\n\n为了使代理能够并发运行，Yew 使用了 [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命周期\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## 代理的类型\n\n### 范围\n\n- 公开 - 在任何给定时间，公共代理的实例最多只有一个。桥梁将在 Web Worker 中生成或连接到已经生成的代理。当没有桥梁连接到此代理时，代理将消失。\n\n- 私有 - 为每个新的桥梁在 Web Worker 中生成一个新的代理。这对于将与浏览器通信的共享但独立的行为从组件中移出是很好的。当连接的桥梁被丢弃时，代理将消失。\n\n- 全局 \\(WIP\\)\n\n## 代理与组件之间的通信\n\n### 通信桥 (Bridges)\n\n通信桥 (bridge) 是一个组件和代理之间的通信通道。它允许组件向代理发送消息，并接收来自代理的消息。\n\n`use_bridge` 钩子也提供了在函数组件中创建桥梁的功能。\n\n### 派发器 (Dispatchers)\n\n派发器 (Dispatchers) 允许组件和代理之间进行单向通信，组件以此方式向代理发送消息。\n\n## 开销\n\n代理使用 Web Workers（即私有和公开）。它们在发送和接收消息时会产生序列化开销。代理使用 [bincode](https://github.com/bincode-org/bincode) 与其他线程通信，因此成本比仅调用函数要高得多。\n\n## 进一步阅读\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 示例展示了组件如何向代理发送消息并接收来自代理的消息。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: '使用 classes! 宏处理 CSS 类'\ndescription: '用一个方便的宏来处理 CSS 类'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew 并没有提供原生的 CSS-in-Rust 解决方案，但通过提供编程方式与 HTML `class` 属性交互的方式来辅助样式。\n\n## `classes!` 宏\n\n`classes!` 宏和相关的 `Classes` 结构简化了 HTML 类的使用：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n更多 CSS 相关的内容请参见[这个文档](../../more/css)。\n\n## 内联样式\n\n目前 Yew 并没有提供特殊的辅助工具来处理通过 `style` 属性指定的内联样式，但你可以像处理其他 HTML 属性一样处理它：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n更多 CSS 相关的内容请参见[这个文档](../../more/css)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: '使用 html! 宏处理 HTML'\ndescription: '这是 HTML，但不完全是！'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n你可以使用 `html!` 宏编写类似 HTML 的表达式。Yew 会在后台将其转换为表达 DOM 的 Rust 代码。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\n类似于格式化表达式，您可以通过使用花括号将周围上下文的值嵌入 HTML 中：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n使用 `html!` 有一个重要的规则 - 您只能返回一个包装节点。为了渲染多个元素的列表，`html!` 允许使用空标签（Fragments）。空标签是没有名称的标签，它们本身不会产生 HTML 元素。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// 错误：只允许一个根 HTML 元素\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修复：使用 HTML 空标签包裹\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n更多关于 Yew 和 HTML 的内容请参见[更多 HTML](concepts/html/introduction.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'Javascript 与 Rust'\ndescription: '在 Rust 中使用 JavaScript'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew 在一个地方集中了一个可重用的 UI 部分可能需要的所有内容 - rust 文件，同时也在必要时保持底层技术的可访问性。\n\n截至今天，WebAssembly 对于 DOM 交互还不完全支持。这意味着即使在 Yew 中，我们有时也依赖于调用 JavaScript。接下来是涉及的库的概述。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一个在 JavaScript 和 Rust 函数之间建立调用桥梁的库和工具。\n\n我们强烈建议您查看他们的[文档](https://wasm-bindgen.github.io/wasm-bindgen/)和我们的[快速指南](./wasm-bindgen.mdx)。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 为 Web API 提供了绑定，并允许我们以一种经过 Rust 处理和安全的方式编写 JavaScript 代码。\n\n示例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n再次强调，我们强烈建议您查看他们的[文档](https://wasm-bindgen.github.io/wasm-bindgen/)和我们的[快速指南](./web-sys.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一个在 JavaScript 和 Rust 函数之间建立调用桥梁的库和工具。它是由 [Rust 和 WebAssembly 工作组](https://rustwasm.github.io/) 使用 Rust 构建的。\n\nYew 使用 `wasm-bindgen` 通过一些 crate 与浏览器进行交互：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\n本节将从更抽象的层次上探讨这些 crate，以便更容易地理解和使用 Yew 中的 `wasm-bindgen` API。要了解有关 `wasm-bindgen` 及其相关 crate 的更深入指南，请查看 [`wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/)。\n\n有关上述 crate 的文档，请查看 [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html)。\n\n:::tip\n使用 `wasm-bindgen` doc.rs 搜索来查找已使用 `wasm-bindgen` 导入的浏览器 API 和 JavaScript 类型。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\n这个 crate 为上面的其他 crate 提供了许多构建块。在本节中，我们只会涵盖 `wasm-bindgen` crate 的两个主要领域，即宏和一些您会一遍又一遍看到的类型/特性。\n\n### `#[wasm_bindgen]` macro\n\n`#[wasm_bindgen]` 宏提供了 Rust 和 JavaScript 之间的接口，提供了一个在两者之间进行转换的系统。使用这个宏更为高级，除非您要使用外部 JavaScript 库，否则不应该使用它。`js-sys` 和 `web-sys` crate 为内置 JavaScript 类型和浏览器 API 提供了 `wasm-bindgen` 定义。\n\n让我们通过一个简单的示例来使用 `#[wasm-bindgen]` 宏来导入一些特定版本的 [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 函数。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// 首先让我们手动绑定 `console.log`，而不使用 `web_sys` 的帮助。\n// 在这里，我们手动编写 `#[wasm_bindgen]` 注解，我们程序的正确性取决于这些注解的正确性！\n#[wasm_bindgen]\nextern \"C\" {\n    // 在这里使用 `js_namespace` 来绑定 `console.log(..)` 而不是只有 `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` 是多态的，所以我们可以使用多个签名绑定它。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 多个参数也是可以的！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// 使用导入的函数！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_这个示例是基于 [1.2 使用 console.log 的 `wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) 改编的。_\n\n### 模拟继承\n\n在 JavaScript 类之间的继承是 JavaScript 语言的核心特性，DOM（文档对象模型）是围绕它设计的。当使用 `wasm-bindgen` 导入类型时，您还可以添加描述它们继承关系的属性。\n\n在 Rust 中，这种继承关系使用 [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) 和 [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) 特性来表示。这里举个例子可能会有所帮助；假设您有三种类型 `A`、`B` 和 `C`，其中 `C` 扩展了 `B`，而 `B` 又扩展了 `A`。\n\n在导入这些类型时，`#[wasm-bindgen]` 宏将按照以下方式实现 `Deref` 和 `AsRef` 特性：\n\n- `C` 可以 `Deref` 到 `B`\n- `B` 可以 `Deref` 到 `A`\n- `C` 可以被 `AsRef` 到 `B`\n- `C` 和 `B` 都可以被 `AsRef` 到 `A`\n\n这些实现允许您在 `C` 的实例上调用 `A` 的方法，并将 `C` 用作 `&B` 或 `&A`。\n\n需要注意的是，使用 `#[wasm-bindgen]` 导入的每种类型都有相同的根类型，您可以将其视为上面示例中的 `A`，这种类型是 [`JsValue`](#jsvalue)，下面有它的部分。\n\n_[`wasm-bindgen` 指引中的 extends 部分](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\n这是 JavaScript 拥有的对象的表示，这是 `wasm-bindgen` 的根捕获类型。任何来自 `wasm-bindgen` 的类型都是 `JsValue`，这是因为 JavaScript 没有强类型系统，因此接受变量 `x` 的任何函数都不定义其类型，因此 `x` 可以是有效的 JavaScript 值；因此 `JsValue`。如果您正在使用接受 `JsValue` 的导入函数或类型，那么任何导入的值在技术上都是有效的。\n\n`JsValue` 可以被函数接受，但该函数可能仍然只接受某些类型，这可能会导致 panic - 因此在使用原始 `wasm-bindgen` API 时，请检查导入的 JavaScript 的文档，以确定是否会在该值不是某种类型时引发异常（panic）。\n\n_[`JsValue` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)。_\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust 有一个强类型系统，而 JavaScript……没有😞。为了让 Rust 保持这些强类型但仍然方便，WebAssembly 工作组提出了一个非常巧妙的特性 `JsCast`。它的工作是帮助您从一个 JavaScript \"类型\" 转换到另一个 \"类型\"，这听起来很模糊，但它意味着如果您有一个类型，您知道它是另一个类型，那么您可以使用 `JsCast` 的函数从一个类型跳到另一个类型。当使用 `web-sys`、`wasm_bindgen`、`js-sys` 时，了解这个很好的特性 - 您会注意到许多类型将从这些 crate 中实现 `JsCast`。\n\n`JsCast` 提供了转换的检查和不检查方法 - 因此在运行时，如果您不确定某个对象是什么类型，您可以尝试将其转换，这将返回可能的失败类型，如 [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) 和 [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)。\n\n一个常见的例子是在 [`web-sys`](./web-sys.mdx) 中，当您尝试获取事件的目标时。您可能知道目标元素是什么，但 [`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API 总是会返回一个 [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)。\n您需要将其转换为元素类型，以便调用其方法。\n\n```rust\n// 需要先导入这个 Trait\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // 也许目标是一个选择元素？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 做点别的\n        return;\n    }\n\n    // 如果它能确定不是一个选择元素，那么我可以肯定它是一个输入元素！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) 方法是一个检查的转换，返回一个 `Option<&T>`，这意味着如果转换失败，则可以再次使用原始类型，因此返回 `None`。[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 方法将消耗 `self`，这是 Rust 中 `into` 方法的约定，返回的类型是 `Result<T, Self>`。如果转换失败，则原始的 `Self` 值将在 `Err` 中返回。您可以再试一次或对原始类型进行其他操作。\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 类型提供了一种将 Rust 闭包传递到 JavaScript 的方法，出于健全性原因，传递给 JavaScript 的闭包必须具有 `'static` 生命周期。\n\n这种类型是一个“句柄”，意味着每当它被丢弃时，它将使其引用的 JS 闭包无效。在 `Closure` 被丢弃后，对 JS 中闭包的任何使用都将引发异常。\n\n当您使用接受类型 [`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 的 `js-sys` 或 `web-sys` API 时，通常会使用 `Closure`。在 [Events](../html/events.mdx) 页面的 [Using `Closure` 部分](../html/events.mdx#using-closure-verbose) 中可以找到在 Yew 中使用 `Closure` 的示例。\n\n_[`Closure` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` crate 提供了 JavaScript 标准内置对象的绑定/导入，包括它们的方法和属性。\n\n这不包括任何 Web API，因为这是 [`web-sys`](./web-sys.mdx) 的作用！\n\n_[`js-sys` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` crate 提供了一个桥梁，用于将 JavaScript Promise 类型作为 Rust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 进行处理，并包含将 Rust Future 转换为 JavaScript Promise 的实用程序。当在 Rust（wasm）中处理异步或其他阻塞工作时，这可能很有用，并提供了与 JavaScript 事件和 JavaScript I/O 原语进行交互的能力。\n\n目前这个 crate 中有三个主要接口：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   一个使用 [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) 构造的类型，然后可以用作 `Future<Output=Result<JsValue, JsValue>>`。如果 `Promise` 被解析，这个 `Future` 将解析为 `Ok`，如果 `Promise` 被拒绝，则解析为 `Err`，分别包含 `Promise` 的解析或拒绝值。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   将 Rust `Future<Output=Result<JsValue, JsValue>>` 转换为 JavaScript `Promise`。未来的结果将转换为 JavaScript 中的已解析或已拒绝 `Promise`。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   在当前线程上生成一个 `Future<Output = ()>`。这是在 Rust 中运行 Future 的最佳方法，而不是将其发送到 JavaScript。\n\n_[`wasm-bindgen-futures` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` 将是 Yew 中 `wasm-bindgen-futures` crate 中最常用的部分，因为这有助于使用具有异步 API 的库。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // 控制台输出 \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew 还在某些 API 中添加了对 futures 的支持，最值得注意的是您可以创建一个接受 `async` 块的 `callback_future` - 这在内部使用了 `spawn_local`。\n\n_[`spawn_local` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys crate 为 Web API 提供绑定。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 为 Web API 提供绑定。这是从浏览器 WebIDL 生成的，这就是为什么有些名称如此之长，有些类型如此模糊的原因。\n\n## `web-sys` 中的特性 (features)\n\n`web-sys` crate 中启用了所有特性可能会给 Wasm 应用程序增加很多冗余。为了解决这个问题，大多数类型都是通过启用 features 进行控制的，这样你只需要包含你的应用程序所需的类型。Yew 启用了 `web-sys` 的几个特性，并在其公共 API 中公开了一些类型。你通常需要自行将 `web-sys` 添加为依赖项。\n\n## `web-sys` 中的继承\n\n在[模拟继承](./wasm-bindgen.mdx#simulating-inheritance)部分，你可以了解到 Rust 通常提供了一种模拟 JavaScript 中继承的方法。这在 `web-sys` 中非常重要，因为了解一个类型上有哪些方法意味着了解它的继承。\n\n这一部分将查看一个特定的元素，并使用 Rust 调用 [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) 列出其继承，直到该值为 [`JsValue`](./wasm-bindgen.mdx#jsvalue)。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement 是 HTML 中的 <textarea>。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意我们现在已经从 web-sys 类型转移到内置的 JavaScript 类型，\n    // 这些类型在 js-sys crate 中。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意我们现在已经从 js-sys 类型转移到 wasm-bindgen crate 中的根 JsValue。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // 这样使用 deref 意味着我们必须手动遍历继承树。\n    // 但是，您可以在 HtmlTextAreaElement 类型上调用 JsValue 方法。\n    assert!(!text_area.is_string());\n\n    // 这个空函数只是为了证明我们可以将 HtmlTextAreaElement 作为 &EventTarget 传递。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // 编译器将沿着 deref 链向下走，以匹配这里的类型。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 实现允许您将 HtmlTextAreaElement 视为 &EventTarget。\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[`wasm-bindgen` 指引中的 `web-sys` 继承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)_\n\n## `NodeRef` 中的 `Node`\n\nYew 使用 [`NodeRef`](concepts/function-components/node-refs.mdx) 来提供一种方式来保留由 [`html!`](concepts/html/introduction.mdx) 宏创建的 `Node` 的引用。`NodeRef` 中的 `Node` 指的是 [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html)。`NodeRef::get` 方法将返回一个 `Option<Node>` 值，但是，在 Yew 中，大多数情况下，您希望将此值转换为特定元素，以便使用其特定方法。如果存在，可以使用 [`JsCast`](./wasm-bindgen.mdx#JsCast) 对 `Node` 值进行转换，但是 Yew 提供了 `NodeRef::cast` 方法来执行此转换，以方便使用，因此您不一定需要为 `JsCast` 特性包含 `wasm-bindgen` 依赖项。\n\n下面的两个代码块本质上是相同的，第一个使用 `NodeRef::cast`，第二个使用 [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 在 `NodeRef::get` 返回的 `web_sys::Node` 上。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // 在这里处理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // 在这里处理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript 重构为 Rust 的示例\n\n这一节展示了如何将与 Web API 交互的 JavaScript 代码示例重写为 Rust 中的 `web-sys`。\n\n### JavaScript 示例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e 为鼠标事件对象\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 元素内的 x 位置。\n    var y = e.clientY - rect.top // 元素内的 y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### 用 `web-sys` 重写的示例\n\n仅使用 `web-sys`，上面的 JavaScript 示例可以这样实现：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 需要启用所有我们想要使用的 web-sys 特性！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 我们现在需要保存 `mousemove` 闭包，以便在事件触发时闭包仍然在内存中。\n```\n\n这个版本更加冗长，但你可能会注意到其中的一部分是由于失败类型提醒我们，一些函数调用有必须保持的不变量，否则将在 Rust 中引发 panic。另一个冗长的部分是调用 `JsCast` 来将不同类型转换为特定类型，以便调用其特定方法。\n\n### 用 Yew 重写的示例\n\n在 Yew 中，您将主要创建 [`Callback`](concepts/function-components/callbacks.mdx) 以在 [`html!`](concepts/html/introduction.mdx) 宏中使用，因此示例将使用这种方法，而不是完全复制上面的方法：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# 我们需要启用 `DomRect` 特性以使用 `get_bounding_client_rect` 方法。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 补充依赖库\n\n`web-sys` 是 Web API 的原始绑定，因此在 Rust 中会有一些痛苦，因为它并不是为 Rust 或甚至强类型系统设计的，这就是社区 crate 提供了对 `web-sys` 的抽象，以提供更符合 Rust 习惯的 API。\n\n_[补充依赖库清单](/community/external-libs)_\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/contexts.mdx",
    "content": "---\ntitle: '上下文 (Contexts)'\nsidebar_label: Contexts\ndescription: '使用上下文传递深度嵌套数据'\n---\n\n通常，数据是通过 props 从父组件传递到子组件。\n但是，如果必须通过中间的许多组件传递它们，或者如果应用程序中的许多组件需要相同的信息，传递 props 可能会变得冗长和烦人。\n上下文解决了这个问题，允许父组件使数据可用于其下方树中的任何组件，无论多深，而无需通过 props 传递它们。\n\n## 使用 props 的问题：\"Prop Drilling\"\n\n传递 [props](./function-components/properties.mdx) 是从父组件直接传递数据到子组件的好方法。\n但是，当需要通过深层嵌套的组件树传递数据或多个组件共享相同的数据时，传递 props 变得繁琐。\n一种常见的数据共享解决方案是将数据提升到一个共同的祖先，并使子组件将其作为 props 接收。\n然而，这可能导致 props 必须通过多个组件才能到达需要它的组件。\n这种情况称为 \"Prop Drilling\"。\n\n考虑以下示例，它通过 props 传递主题：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App 根节点\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n我们通过 `Navbar` 传递主题设定，以便它可以到达 `Title` 和 `NavButton`。\n如果 `Title` 和 `NavButton` 这些需要访问主题的组件可以直接访问主题而不必通过 prop 传递，那就更好了。\n上下文解决了这个问题，允许父组件将数据（在这种情况下是主题）传递给其子组件。\n\n## 使用上下文\n\n### 步骤 1：提供上下文\n\n需要一个上下文提供者来消费上下文。`ContextProvider<T>`，其中 `T` 是用作提供者的上下文结构体。\n`T` 必须实现 `Clone` 和 `PartialEq`。`ContextProvider` 是其子组件将拥有上下文的组件。\n当上下文更改时，子组件会重新渲染。一个结构体用于定义要传递的数据。`ContextProvider` 可以这样使用：\n\n```rust\nuse yew::prelude::*;\n\n/// App 主题\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// 主组件\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` 是 `Rc<UseStateHandle<Theme>>` 类型，而我们需要 `Theme`\n        // 所以我们对它进行解引用。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // 这里的每个子组件及其子组件都将访问此上下文。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// 工具栏\n/// 此组件可以访问上下文。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// 放置在 `Toolbar` 中的按钮\n/// 由于此组件是组件树中 `ThemeContextProvider` 的子组件，它也可以访问上下文。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### 步骤 2：使用上下文\n\n#### 函数组件\n\n`use_context` 钩子用于在函数组件中使用上下文。\n请参阅 [use_context 文档](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) 了解更多信息。\n\n#### 结构体组件\n\n我们有两种选择在结构体组件中使用上下文：\n\n- [高阶组件](../advanced-topics/struct-components/hoc)：一个高阶函数组件将使用上下文并将数据传递给需要它的结构体组件。\n- 直接在结构体组件中使用上下文。请参阅 [结构体组件作为消费者的示例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## 使用场景\n\n通常，如果某些数据需要在树的不同部分的远程组件中使用，上下文可能会对你有所帮助。\n以下是一些这样的例子：\n\n- **主题**：你可以在应用程序的顶部放置一个上下文来保存你的应用程序主题，并使用它来调整视觉外观，如上例所示。\n- **当前用户帐户**：在许多情况下，组件需要知道当前登录的用户。你可以使用上下文将当前用户对象提供给组件。\n\n### 使用上下文前的考虑\n\n上下文非常容易使用，这也使得它们非常容易被误用/过度使用。\n仅仅因为你可以使用上下文将 props 共享给多个层级深的组件，并不意味着你应该这样做。\n\n例如，你可以提取一个组件并将该组件作为子组件传递给另一个组件。例如，\n你可能有一个 `Layout` 组件，它将 `articles` 作为 prop 并传递给 `ArticleList` 组件。\n你应该重构 `Layout` 组件，使其接受子组件作为 props 并显示 `<Layout> <ArticleList {articles} /> </Layout>`。\n\n## 修改子组件的上下文值\n\n由于 Rust 的所有权规则，上下文不能有一个可以被子组件调用的 `&mut self` 方法。\n要修改上下文的值，我们必须将其与 reducer 结合使用。这可以通过使用\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) 钩子来完成。\n\n[上下文示例](https://github.com/yewstack/yew/tree/master/examples/contexts) 演示了使用上下文的可变上下文\n\n## 进一步阅读\n\n- [上下文示例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: '回调 (Callbacks)'\n---\n\n回调函数用于在组件树中向上传递信息，以及在事件处理期间与其他组件（如代理或 DOM）进行通信。在内部，回调函数的类型只是一个 `Fn`，并且被包装在 `Rc` 中，以便它们可以被廉价地克隆。\n\n如果您想手动调用回调函数，可以使用 `emit` 函数。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // 调用回调函数\n// web_sys::console::log_1(&result.into()); // 如果取消注释，将打印 \"Bye Bob\"\n```\n\n## 将回调函数作为属性传递\n\n在 yew 中的一个常见模式是创建一个回调函数，并将其作为属性传递给子组件。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 然后提供属性 (Props)\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // 如果取消注释，这里会打印文本\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM 事件和回调函数\n\n回调函数也用于连接到 DOM 事件。\n\n例如，这里我们定义了一个回调函数，当用户点击按钮时将会调用：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // 如果取消注释，这里会打印文本\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子元素 (Children)'\n---\n\n`Children` 是一种特殊的属性类型，允许您接收嵌套的 `Html`，就像 html 子元素一样提供。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` 键很重要！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // 可以靠这种方式转发子元素\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/communication.mdx",
    "content": "---\ntitle: '组件之间的通信'\n---\n\n## 父组件向子组件发送消息\n\n将数据作为 [props](./properties) 传递，这会导致重新渲染，这是向子组件传递消息的方法。\n\n## 子组件向父组件发送消息\n\n通过 props 传递一个回调，子组件在事件上可以调用。[示例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/generics.mdx",
    "content": "---\ntitle: '泛型组件'\ndescription: '函数组件的 #[component] 属性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 属性也适用于用于创建泛型组件的泛型函数。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// 之后可以像这样使用\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// 或者\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: '自定义 Hooks'\n---\n\n## 定义自定义 Hooks\n\n组件的有状态逻辑可以通过创建自定义 Hooks 来提取为可重用的函数。\n\n假设我们希望创建一个事件监听器，监听 `window` 对象上的事件。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\n这段代码有一个问题：逻辑无法被另一个组件重用。如果我们构建另一个监听不同事件的组件，而不是复制代码，我们可以将逻辑移入自定义 hook。\n\n我们将首先创建一个名为 `use_event` 的新函数。`use_` 前缀表示函数是一个 hook。此函数将接受一个事件目标、一个事件类型和一个回调。所有 hook 必须在其函数定义上标记为 `#[hook]`。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\n这个简单的 hook 可以通过组合内置 hook 创建。在本例中，我们将使用 `use_effect_with` hook，因此当 hook 参数发生变化时，可以重新创建事件监听器。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\n尽管这种方法在几乎所有情况下都有效，但它无法用于编写像我们已经使用的预定义 hook 那样的基本 hook。\n\n查看 [docs.rs](https://docs.rs/yew) 上的文档以及 `hooks` 目录，查看预定义 hook 的实现。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks 是一类能够存储状态和执行副作用的函数。\n\nYew 提供了一些预定义的 hooks。您也可以创建自己的 hooks，或者发现许多[社区制作的 hooks](/community/awesome#hooks)。\n\n## Hooks 规则\n\n1. 每个 Hook 函数的名称必须以 `use_` 开头\n2. Hooks 只能在以下位置使用：\n    - 函数/ Hook 的顶层\n    - 函数/ Hook 内的块，只要它没有被分支\n    - 函数/ Hook 内顶层 `if` 表达式的条件\n    - 函数/ Hook 内顶层 `match` 表达式的选择器\n3. 每次渲染时，Hooks 必须以相同的顺序调用。只有在使用 [Suspense](../../suspense.mdx) 时才允许提前返回\n\n这些规则由编译时或运行时错误来执行。\n\n### 预定义 Hooks\n\nYew 提供了以下预定义 Hooks：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\n这些 hooks 的文档可以在 [Yew API 文档](https://yew-rs-api.web.app/next/yew/functional/)中找到。\n\n### 自定义 Hooks\n\n有些情况下，您可能希望定义自己的 Hooks，以将组件中的可能具有状态的逻辑封装到可重用的函数中。\n\n## 进一步阅读\n\n- React 文档中有一个关于 [React hooks](https://reactjs.org/docs/hooks-intro.html) 的部分。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函数组件'\nslug: /concepts/function-components\n---\n\n让我们重新回顾一下之前的标语：\n\n> Yew 的核心思想是将可重用的 UI 部分所需的所有内容集中在一个地方 - Rust 文件中。\n\n我们将通过引入将定义应用程序的逻辑和呈现行为的概念来完善这个陈述：\"组件\"。\n\n## 什么是组件？\n\n组件是 Yew 的构建块。\n\n它们应当：\n\n- 以 [Props](./properties.mdx) 的形式接受参数\n- 可以拥有自己的状态\n- 计算用户可见的 HTML 片段（DOM）\n\n## Yew 组件的两种风味\n\n您当前正在阅读有关函数组件的内容 - 这是在开始使用 Yew 时以及在编写简单的呈现逻辑时编写组件的推荐方式。\n\n还有一种更高级但不太容易访问的编写组件的方式 - [结构组件](advanced-topics/struct-components/introduction.mdx)。它们允许非常详细的控制，尽管大多数情况下您不需要那么详细的控制。\n\n## 创建函数组件\n\n要创建一个函数组件，请将 `#[component]` 属性添加到一个函数中。按照惯例，函数的名称采用 PascalCase，与 `html!` 宏中的普通 html 元素形成对比。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 然后在其他地方，您可以在 `html!` 中使用组件\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## 组件内部发生了什么\n\n在渲染时，Yew 将构建这些组件的虚拟树。它将调用每个（函数）组件的 view 函数来计算 DOM 的虚拟版本（VDOM），您作为库用户将其视为 `Html` 类型。对于上面的示例，这将如下所示：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n当需要更新时，Yew 将再次调用 view 函数，并将新的虚拟 DOM 与其之前的版本进行协调，并仅将新的/更改的/必要的部分传 播到实际的 DOM。这就是我们所说的 **渲染**。\n\n:::note\n\n实际上，`Html` 只是 `VNode` 的别名 - 一个虚拟节点。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: '节点引用'\ndescription: 'DOM 外部访问'\n---\n\n`ref` 属性可以用于将 `NodeRef` 附加到 HTML 元素上。在回调中，您可以获取 `ref` 附加到的 DOM `Element`。这可以用于在 `view` 生命周期方法之外对 DOM 进行更改，检索 `<input>` 的值以及通过 javascript API 直接与 DOM 交互。\n\n这对于获取 canvas 元素或滚动到页面的不同部分很有用。\n\n:::caution\n不要手动修改 Yew 渲染的 DOM 树。如果不确定，请将 `NodeRef` 视为只读访问。\n:::\n\n## 进一步阅读\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` 示例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '属性 (Properties)'\ndescription: '父子组件通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n属性 (Properties) 通常被简写为 \"Props\"。\n\n:::\n\n属性 (Properties) 是组件的参数，Yew 可以监视这些参数。\n\n在组件的属性中使用一个类型之前，它必须实现 `Properties` trait。\n\n## 响应性\n\n在重新渲染时，Yew 在协调虚拟 DOM 时检查属性是否已更改，以了解是否需要重新渲染嵌套组件。这样，Yew 可以被认为是一个非常具有响应性的框架，因为来自父组件的更改总是会向下传播，视图永远不会与来自属性/状态的数据不同步。\n\n:::tip\n\n如果您尚未完成 [教程](../../tutorial)，请尝试并自行测试这种响应性！\n\n:::\n\n## 派生宏\n\nYew 提供了一个派生宏，可以轻松地在结构体上实现 `Properties` trait。\n\n您派生 `Properties` 的类型也必须实现 `PartialEq`，以便 Yew 可以进行数据比较。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函数组件中使用\n\n属性 `#[component]` 允许在函数参数中选择性地接收 Props。要提供它们，可以通过 `html!` 宏中的属性进行赋值。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// 然后提供属性\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 没有属性需要提供\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生宏字段属性\n\n在派生 `Properties` 时，默认情况下所有字段都是必需的。\n\n以下属性允许您为属性提供默认值，当父组件没有设置它们时将使用这些默认值。\n\n:::tip\n属性在 Rustdoc 生成的文档中是不可见的。您的属性的文档字符串应该提到一个属性是否是可选的，以及它是否有一个特殊的默认值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` trait 的字段类型的默认值初始化属性值。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 这样使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 来初始化属性值。`value` 可以是返回字段类型的任何表达式。\n\n例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。当属性被构造时，表达式会被评估，且没有给出明确的值。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// 这样使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n调用 `function` 来初始化属性值。`function` 应该具有 `FnMut() -> T` 签名，其中 `T` 是字段类型。当没有为该属性给出明确的值时，将调用该函数。\n这个函数在属性被构造时被调用。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// 使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的性能开销\n\n内部属性是以引用计数的智能指针传递的。这意味着只有一个共享指针被传递到组件树中的属性，这样就能节约克隆整个属性的高昂成本。\n\n:::tip\n`AttrValue` 是我们用于属性值的自定义类型，这样就不用将它们定义为 String 或其他类似克隆成本高昂的类型了。\n:::\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n该宏使用与结构表达式相同的语法，只是您不能使用属性或基本表达式 (`Foo { ..base }`)。类型路径可以直接指向属性 (`path::to::Props`)，也可以指向组件的关联属性 (`MyComp::Properties`)。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 注意我们不需要指定 name 属性\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自动生成属性 (yew-autoprops)\n\n为了简化您的开发流程，您还可以使用宏 `#[autoprops]`（来自 `yew-autoprops` 包）自动生成 `Properties` 结构体。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] 宏必须出现在 #[component] 之前，顺序很重要\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 结构体 \"GreetingsProps\" 将会被自动生成。\n//\n// `is_loading` 将作为值传递给组件，而 `message` 和 `name` 将使用引用，因为定义中有一个前导的 `&`。\n```\n\n## 评估顺序\n\n属性按照指定的顺序进行评估，如下例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n虽然几乎任何 Rust 类型都可以作为属性传递，但有一些反模式应该避免。这些包括但不限于：\n\n1. 使用 `String` 类型而不是 `AttrValue`。 <br />\n   **为什么不好？** `String` 克隆成本高昂。当属性值与钩子和回调一起使用时，通常需要克隆。`AttrValue` 是一个引用计数的字符串 (`Rc<str>`) 或一个 `&'static str`，因此非常便宜克隆。<br />\n   **注意**：`AttrValue` 在内部是来自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看该包以了解更多信息。\n2. 使用内部可变性。 <br />\n   **为什么不好？** 内部可变性（例如 `RefCell`、`Mutex` 等）应该 _通常_ 避免使用。它可能会导致重新渲染问题（Yew 不知道状态何时发生了变化），因此您可能需要手动强制重新渲染。就像所有事物一样，它有其用武之地。请谨慎使用。\n3. 使用 `Vec<T>` 类型而不是 `IArray<T>`。 <br />\n   **为什么不好？** `Vec<T>`，就像 `String` 一样，克隆成本也很高。`IArray<T>` 是一个引用计数的切片 (`Rc<[T]>`) 或一个 `&'static [T]`，因此非常便宜克隆。<br />\n   **注意**：`IArray` 可以从 [implicit-clone](https://crates.io/crates/implicit-clone) 导入。查看该包以了解更多信息。\n4. 您发觉可能的新内容。您是否遇到了一个希望早点了解清楚的边缘情况？请随时创建一个问题或向本文档提供修复的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一个实验性包，允许您根据函数的参数动态创建 Props 结构体。如果属性结构体永远不会被重用，这可能会很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '纯组件'\n---\n\n每个函数组件都是一个[纯](https://zh.wikipedia.org/wiki/%E7%BA%AF%E5%87%BD%E6%95%B0)函数，它接受一个属性对象并返回一个 `Html` 对象。纯函数是指在给定相同输入时，总是返回相同输出的函数。\n\n这个例子是一个纯组件。对于给定的属性 `is_loading`，它总是返回相同的 `Html`，没有任何副作用。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n如果您有一个内部纯组件，它不使用 hooks 和其他组件机制，您通常可以将其编写为返回 `Html` 的普通函数，从而避免 Yew 运行组件生命周期相关的一些开销。使用 [表达式语法](concepts/html/literals-and-expressions.mdx#expressions) 在 `html!` 中渲染它们。\n:::\n\n## 非纯组件\n\n您可能想知道，如果组件不使用任何全局变量，那么它是否可以是不“纯”的，因为它只是在每次渲染时调用的固定函数。\n这就是下一个主题 - [hooks](./hooks) 的用武之地。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/state.mdx",
    "content": "---\ntitle: '状态'\n---\n\n## 如何存储状态的一般视图\n\n这个表格可以作为一个指南，帮助您决定哪种状态存储类型最适合您的用例：\n\n| Hook             | 类型                       | 何时渲染?                        | 作用域                   |\n| ---------------- | -------------------------- | -------------------------------- | ------------------------ |\n| [use_state]      | `T`                        | 被设置一个值                     | 组件内部实例             |\n| [use_state_eq]   | `T: PartialEq`             | 被设置一个不同的值               | 组件内部实例             |\n| [use_reducer]    | `T: Reducible`             | 被调用归纳                       | 组件内部实例             |\n| [use_reducer_eq] | `T: Reducible + PartialEq` | 被调用归纳，归纳后的值与之前不同 | 组件内部实例             |\n| [use_memo]       | `Deps -> T`                | 依赖项发生变化                   | 组件内部实例             |\n| [use_callback]   | `Deps -> Callback<E>`      | 依赖项发生变化                   | 组件内部实例             |\n| [use_mut_ref]    | `T`                        | -                                | 组件内部实例             |\n| 全局静态常量     | `T`                        | -                                | 全局，任何位置都可以使用 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/classes.mdx",
    "content": "---\ntitle: '类'\ndescription: '一个方便的宏来处理类'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 类\n\n`Classes` 结构体可以用来处理 HTML 类。\n\n将字符串推送到集合时，`Classes` 确保每个类都有一个元素，即使单个字符串可能包含多个类。\n\n`Classes` 也可以通过使用 `Extend`（即 `classes1.extend(classes2)`）或 `push()`（即 `classes1.push(classes2)`）来合并。任何实现 `Into<Classes>` 的类型都可以推送到现有的 `Classes` 上。\n\n`classes!` 是一个方便的宏，它创建一个单一的 `Classes`。它的输入接受一个逗号分隔的表达式列表。唯一的要求是每个表达式都实现了 `Into<Classes>`。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 接受类的组件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/components.mdx",
    "content": "---\ntitle: '组件'\ndescription: '使用组件层次结构创建复杂的布局'\n---\n\n## 基础\n\n组件可以在 `html!` 宏中使用：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // 没有属性\n        <MyComponent />\n\n        // 使用属性\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // 一次性提供所有属性\n        <MyComponentWithProps ..props.clone() />\n\n        // 使用变量中的属性，并覆盖特定值\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## 嵌套\n\n如果组件在其 `Properties` 中有一个 `children` 字段，它可以接受子组件/元素\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` 宏允许您使用 `..props` 语法传递一个基本表达式，而不是单独指定每个属性，类似于 Rust 的[函数式更新语法](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax)。\n这个基本表达式必须出现在传递任何单独的 props 之后。\n当传递一个带有 `children` 字段的基本 props 表达式时，`html!` 宏中传递的子元素将覆盖已经存在于 props 中的子元素。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子元素将覆盖 props.children\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 相关示例\n\n- [函数化 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [函数化路由](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '条件渲染'\ndescription: '在 html 中有条件地渲染节点！'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If 块\n\n要有条件地渲染一些标记，我们将其包装在 `if` 块中：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/elements.mdx",
    "content": "---\ntitle: '元素'\ndescription: '支持 HTML 和 SVG 元素'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM 节点\n\n在 Yew 中手动创建或管理 DOM 节点的原因有很多，比如与可能与受管理组件冲突的 JS 库集成。\n\n使用 `web-sys`，您可以创建 DOM 元素并将其转换为 `Node` - 然后可以使用 `VRef` 将其用作 `Html` 值：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // 带记忆能力的函数，只会执行一次\n    let node = use_memo(\n        (),\n        |_| {\n            // 从文档中创建一个 div 元素\n            let div: Element = document().create_element(\"div\").unwrap();\n            // 添加内容、类等\n            div.set_inner_html(\"Hello, World!\");\n            // 将 Element 转换为 Node\n            let node: Node = div.into();\n            // 将该 Node 作为 Html 值返回\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo 返回的是 Rc 指针，所以我们需要解引用和克隆\n    (*node).clone()\n}\n\n```\n\n## 动态标签名\n\n在构建高阶组件时，您可能会发现自己处于一个标签名不是静态的情况。例如，您可能有一个 `Title` 组件，根据级别属性可以渲染从 `h1` 到 `h6` 的任何内容。而不是使用一个大的匹配表达式，Yew 允许您动态设置标签名，使用 `@{name}`，其中 `name` 可以是返回字符串的任何表达式。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 逻辑值属性\n\n一些内容属性（例如 checked、hidden、required）被称为逻辑值属性。在 Yew 中，逻辑值属性需要设置为布尔值：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\n这与以下的 **HTML** 功能上是等价的：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n将逻辑值属性设置为 false 等效于不使用该属性；可以使用逻辑表达式的值：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\n这与以下 **HTML** 结果等价：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 类似字符串的属性\n\n除了一些逻辑值属性，您可能会处理很多类似字符串的 HTML 属性，Yew 有几种选项可以将类似字符串的值传递给组件。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\n它们都是有效的，**但**我们鼓励您更倾向于使用 Yew 的自定义 `AttrValue`，特别是如果您需要克隆或将它们作为属性传递给另一个组件。\n\n## HTML 元素的可选属性\n\n大多数 HTML 属性可以使用可选值（Some(x) 或 None）。这使我们可以在属性被标记为可选时省略该属性。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n如果属性设置为 `None`，则该属性将不会在 DOM 中设置。\n\n## 相关示例\n\n- [内嵌 HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/events.mdx",
    "content": "---\ntitle: '事件'\n---\n\n## 介绍\n\nYew 与 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate 集成，并使用该 crate 中的事件。下面的[表格](#event-types)列出了在 `html!` 宏中接受的所有 `web-sys` 事件。\n\n您仍然可以为下表中未列出的事件添加 [`Callback`](../function-components/callbacks.mdx)，请参见[手动事件监听器](#manual-event-listener)。\n\n## 事件类型\n\n:::tip\n所有的事件类型都在 `yew::events` 下重新导出。\n使用 `yew::events` 中的类型比手动将 `web-sys` 作为依赖项包含在您的 crate 中更容易确保版本兼容性，\n因为您不会使用与 Yew 指定的版本冲突的版本。\n:::\n\n事件监听器的名称是在 `html` 宏中添加事件 `Callback` 时预期的名称：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\n事件名称是监听器名称去掉 \"on\" 前缀，因此 `onclick` 事件监听器监听 `click` 事件。查看本页末尾的[完整事件列表](#available-events)及其类型。\n\n## 事件捕获 {#event-bubbling}\n\nYew 调度的事件遵循虚拟 DOM 层次结构，向上冒泡到监听器。目前，仅支持监听器的冒泡阶段。请注意，虚拟 DOM 层次结构通常（但并非总是）与实际 DOM 层次结构相同。在处理[传送门](../../advanced-topics/portals)和其他更高级技术时，这一区别很重要。对于良好实现的组件，直觉应该是事件从子组件冒泡到父组件。这样，您在 `html!` 中编写的层次结构就是事件处理程序观察到的层次结构。\n\n如果您不想要事件冒泡，可以通过调用\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n在启动应用程序*之前*。这会加快事件处理速度，但某些组件可能会因未收到预期的事件而中断。请谨慎使用！\n\n## 事件委托\n\n可能会让人惊讶的是，事件监听器并不是直接注册在它们被渲染的元素上。相反，事件是从 Yew 应用的子树根节点委托的。不过，事件仍然以其原生形式传递，并且不会创建任何合成形式。这可能会导致 HTML 监听器中预期的事件与 Yew 中出现的事件之间的不匹配。\n\n- [`Event::current_target`] 指向 Yew 子树根节点，而不是添加监听器的元素。如果您想访问底层的 `HtmlElement`，请使用 [`NodeRef`](../function-components/node-refs.mdx)。\n- [`Event::event_phase`] 始终是 [`Event::CAPTURING_PHASE`]。在内部，事件将表现得像是在冒泡阶段，事件传播将被重放，并且事件会[向上冒泡](#event-bubbling)，即虚拟 DOM 中较高的事件监听器将在较低的事件监听器之后触发。目前，Yew 不支持捕获监听器。\n\n这也意味着由 Yew 注册的事件通常会在其他事件监听器之前触发。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 具备类型的事件目标\n\n:::caution\n在本节中，**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** 始终指的是事件从其派发的元素。\n\n这**不一定**总是指代 `Callback` 所放置的元素。\n:::\n\n在事件 `Callback` 中，您可能希望获取该事件的目标。例如，`change` 事件没有提供任何信息，但用于通知某些内容已更改。\n\n在 Yew 中，以正确的类型获取目标元素可以通过几种方式完成，我们将在这里逐一介绍。调用事件上的 [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) 返回一个可选的 [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 类型，当您想知道输入元素的值时，这可能看起来不是很有用。\n\n在下面的所有方法中，我们将解决相同的问题，以便清楚地了解方法的不同之处，而不是手头的问题。\n\n**问题：**\n\n我们在 `<input>` 元素上有一个 `onchange` `Callback`，每次调用时，我们希望向组件发送一个[更新](components#update) `Msg`。\n\n我们的 `Msg` 枚举如下所示：\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### 使用 `JsCast`\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate 有一个有用的 trait：[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)，它允许我们在类型之间直接转换，只要它实现了 `JsCast` 就行。我们可以谨慎地转换，这涉及运行时检查和处理 `Option` 和 `Result` 的逻辑，或者我们也可以冒险直接强行转换。\n\n多说无益，看代码：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# 需要 wasm-bindgen 用于调用 JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // 当事件被创建时，目标是未定义的，只有在派发时才会添加目标。\n            let target: Option<EventTarget> = e.target();\n            // 事件可能会冒泡，因此此侦听器可能会捕获不是 HtmlInputElement 类型的子元素的事件。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // 你必须了解 target 是 HtmlInputElement，否则调用 value 将是未定义行为（UB）。\n        // 在这里，我们确信这是输入元素，因此我们可以在不检查的情况下将其转换为适当的类型。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` 提供的方法是 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\n和 [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)。\n如你所见，它们允许我们从 `EventTarget` 转换为 [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html)。\n`dyn_into` 方法是谨慎的，因为它会在运行时检查类型是否实际为 `HtmlInputElement`，如果不是则返回\n`Err(JsValue)`。[`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n是一个通用类型，将原来的对象返回给你，以便再次尝试转换为别的类型。\n\n这会儿你可能会想，什么时候可以使用危险版本？在上面的情况下，它是安全的<sup>1</sup>，因为我们将 `Callback` 设置在一个没有子元素的元素上，所以目标只能是同一个元素。\n\n_<sup>1</sup> 只要涉及到 JS 领域，就是安全的。_\n\n### 使用 `TargetCast`\n\n**强烈建议先阅读 [使用 JsCast](#using-jscast)！**\n\n:::note\n`TargetCast` 的设计目的是让新用户了解 `JsCast` 的行为，但范围更小，仅涉及事件及其目标。\n\n选用 `TargetCast` 或 `JsCast` 纯粹是个人偏好，实际您会发现 `TargetCast` 的实现和 `JsCast` 的功能很相似。\n:::\n\n`TargetCast` trait 是在 `JsCast` 基础之上构建的，专门用于从事件中获取类型化的事件目标。\n\n`TargetCast` 是 Yew 的一部分，因此无需添加依赖项即可在事件上使用 trait 方法，但它的工作方式与 `JsCast` 非常相似。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // 你必须清楚 target 是 HtmlInputElement，否则调用 value 将是未定义行为（UB）。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n如果您已经了解了 `JsCast`，或者了解了这个 trait，您可能会发现 `TargetCast::target_dyn_into` 与 `JsCast::dyn_into` 相似，但专门用于事件的目标。`TargetCast::target_unchecked_into` 与 `JsCast::unchecked_into` 类似，因此上面关于 `JsCast` 的所有警告都适用于 `TargetCast`。\n\n### 使用 `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) 可以代替查询给定给 `Callback` 的事件。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n通过 `NodeRef`，你可以忽略事件并使用 `NodeRef::cast` 方法获取一个 `Option<HtmlInputElement>` - 这是可选的，因为在设置 `NodeRef` 之前调用 `cast`，或者类型不匹配时将返回 `None`。\n\n你可能会看到，通过使用 `NodeRef`，我们不必将 `String` 发送回状态，因为我们总是访问 `input_node_ref` - 因此我们可以这样做：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // 对 value 做点什么\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\n您选择哪种方法取决于您的组件和您的偏好，没有所谓的*推荐*方法。\n\n## 手动事件监听器\n\n您可能希望监听 Yew 的 `html` 宏不支持的事件，查看[这里列出的支持的事件](#event-types)。\n\n为了手动向某个元素添加事件监听器，我们需要借助 [`NodeRef`](../function-components/node-refs.mdx)，以便在 `use_effect_with` 中使用 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) 和 [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API 添加监听器。\n\n以下示例将展示如何为虚构的 `custard` 事件添加监听器。所有不受 yew 支持的事件或自定义事件都可以表示为\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html)。如果您需要访问自定义/不受支持事件的特定方法或字段，可以使用\n[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) 的方法将其转换为所需的类型。\n\n### 使用 `Closure`（冗长版本）\n\n直接使用 `web-sys` 和 `wasm-bindgen` 的接口可能有点痛苦……所以要有点心理准备（[感谢 `gloo`，有了更简洁的方法](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 创建您通常会创建的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 对 custard 做点什么..\n                    });\n\n                    // 从 Box<dyn Fn> 创建一个 Closure - 这必须是 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有关 `Closure` 的更多信息，请参见 [wasm-bindgen 指南](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html)。\n\n### 使用 `gloo`（简洁版本）\n\n更方便的方法是使用 `gloo`，更具体地说是 [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)，\n它是 `web-sys`、`wasm-bindgen` 的高层抽象实现。\n\n`gloo_events` 提供了 `EventListener` 类型，可以用于创建和存储事件监听器。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 创建您通常会创建的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 对 custard 做点什么..\n                    });\n\n                    // 从 Box<dyn Fn> 创建一个 Closure - 这必须是 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有关 `EventListener` 的更多信息，请参见 [gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html)。\n\n## 可用事件的完整列表 {#available-events}\n\n| 侦听器名称                  | `web_sys` 事件类型                                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空标签 (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 宏总是需要一个根节点。为了绕过这个限制，您可以使用一个“空标签”（也称为“fragments”）。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// 错误：只允许一个根 HTML 元素\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: '用于生成 HTML 和 SVG 的过程宏'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 宏允许您声明性地编写 HTML 和 SVG 代码。它类似于 JSX（一种允许您在 JavaScript 中编写类似 HTML 的代码的扩展）。\n\n**重要提示**\n\n1. `html! {}` 宏只能接受一个根 HTML 节点（您可以通过使用 [fragments](./fragments.mdx) 或 [iterators](./../html/lists.mdx) 来规避这一点）\n2. 空的 `html! {}` 调用是有效的，不会渲染任何内容\n3. 字面量必须始终用引号引起来并用大括号括起来：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` 宏会将所有标签名称转换为小写。要使用大写字符（某些 SVG 元素所需的字符）请使用[动态标签名称](concepts/html/elements.mdx#dynamic-tag-names)：`html! { <@{\"myTag\"}></@> }`\n\n:::note\n`html!` 宏可能会达到编译器的默认递归限制。如果遇到编译错误，请在 crate 根目录添加类似 `#![recursion_limit=\"1024\"]` 的属性以解决问题。\n:::\n\n## 标签 (Tags) 结构\n\n标签 (Tags) 基于 HTML 标签。组件、元素和列表都基于此标签语法。\n\n标签必须要么自闭合 `<... />`，要么对于每个开始标签都有一个相应的结束标签。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 缺少闭合标签\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 缺少闭合标签\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n方便起见，通常需要闭合标签的元素**允许**自闭合。例如，编写 `html! { <div class=\"placeholder\" /> }` 是有效的。\n:::\n\n创建复杂的嵌套 HTML 和 SVG 布局还是很容易的：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\n如果您使用 Rust 编译器的开发者版本编译 Yew，宏将警告您可能遇到的一些常见陷阱。当然，您可能需要使用稳定版编译器（例如，您的组织可能有政策要求这样做）进行发布构建，但即使您使用的是稳定工具链，运行 `cargo +nightly check` 也可能会标记一些可以改进 HTML 代码的方法。\n\n目前，这些 lint 主要与可访问性相关。如果您有 lint 的想法，请随时[在此问题中发表意见](https://github.com/yewstack/yew/issues/1334)。\n\n## 指定属性和属性\n\n属性与普通 HTML 中的元素设置方式相同：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n属性在元素名称之前用 `~` 指定：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n如果值是一个字面量的话，围绕值的大括号可以省略。\n\n:::\n\n:::note 什么是字面量\n\n字面量是 Rust 中所有有效的[字面量表达式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)。请注意，[负数**不是**字面量](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)，因此必须用大括号括起来 `{-6}`。\n\n:::\n\n:::note 组件属性\n组件属性作为 Rust 对象传递，与此处描述的元素参数 (Attributes) / 属性 (Properties) 不同。\n在[组件属性](../function-components/properties.mdx)中了解更多信息。\n:::\n\n### 特殊属性\n\n有一些特殊属性不直接影响 DOM，而是作为 Yew 虚拟 DOM 的指令。目前有两个这样的特殊属性：`ref` 和 `key`。\n\n`ref` 允许您直接访问和操作底层 DOM 节点。有关更多详细信息，请参阅[Refs](../function-components/node-refs.mdx)。\n\n另一方面，`key` 为元素提供了一个唯一标识符，Yew 可以用于优化目的。\n\n:::info\n[了解更多相关内容](./html/lists)\n:::\n\n## 条件渲染\n\n可以通过使用 Rust 的条件结构来条件性地渲染标记。目前只支持 `if` 和 `if let`。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n阅读[条件渲染](./conditional-rendering.mdx)一节了解更多\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/lists.mdx",
    "content": "---\ntitle: '列表'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 迭代器\n\n从迭代器构建 HTML 有 3 种方法：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` 循环\">\n主要方法是使用 for 循环，与 Rust 中已有的 for 循环相同，但有 2 个关键区别：\n1. 与标准 for 循环不能返回任何内容不同，`html!` 中的 for 循环会被转换为节点列表；\n2. 发散表达式，即 `break`、`continue` 在 `html!` 中的 for 循环体内是不允许的。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` 块\">\n另一种方法是使用 `for` 关键字，这不是原生的 Rust 语法，而是由 HTML 宏用于输出显示迭代器所需的代码。\n当迭代器已经计算好，只需要将其传递给宏时，这种方法比第一种更好。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` 方法\">\n\n最后一种方法是在迭代器的最终转换上调用 `collect::<Html>()`，它返回一个 Yew 可以显示的列表。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 键 (Key) 列表\n\n键 (Key) 列表是一个优化的列表，其中**所有**子元素都有键。\n`key` 是 Yew 提供的一个特殊属性，它为 HTML 元素或组件提供一个唯一标识符，用于 Yew 内部的优化。\n\n:::caution\nKey 只需要在每个列表中是唯一的，与 HTML `id` 的全局唯一性相反。它不应该依赖于列表的顺序。\n:::\n\n始终建议为列表添加键 (key)。\n\n可以通过将唯一的 `String`、`str` 或整数传递给特殊的 `key` 属性来添加键：\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### 性能优化\n\n我们有一个[带有键 (keys) 的列表示例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)可以让你测试性能上的改进，这里是一个简单的测试流程：\n\n1. 进入[在线演示](https://examples.yew.rs/keyed_list)\n2. 添加 500 个元素\n3. 禁用键\n4. 反转列表\n5. 查看 \"最后一次渲染花费了 Xms\"（在撰写本文时，大约为 60ms）\n6. 启用键\n7. 再次反转列表\n8. 查看 \"最后一次渲染花费了 Xms\"（在撰写本文时，大约为 30ms）\n\n截至撰写本文时，对于 500 个组件，速度提高了 2 倍。\n\n### 原理解释\n\n通常，当你迭代时，只需要在每个列表项上添加一个键，数据的顺序可能会发生变化。\n在重新渲染列表时，它用于加速协调过程。\n\n如果没有键，假设你迭代 `[\"bob\", \"sam\", \"rob\"]`，最终得到的 HTML 如下：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n然后在下一次渲染时，如果你的列表更改为 `[\"bob\", \"rob\"]`，Yew 可以删除 id=\"rob\" 的元素，并将 id=\"sam\" 更新为 id=\"rob\"。\n\n如果你为每个元素添加了一个键，初始 HTML 将保持不变，但在使用修改后的列表 `[\"bob\", \"rob\"]` 进行渲染后，Yew 只会删除第二个 HTML 元素，而其他元素则保持不变，因为它可以使用键将它们关联起来。\n\n如果你遇到了一个从一个组件切换到另一个组件的 bug/\"feature\"，但两者都有一个 div 作为最高渲染元素。\nYew 在这些情况下会重用已渲染的 HTML div 作为优化。\n如果你需要该 div 被重新创建而不是被重用，那么你可以添加不同的键，它们将不会被重用。\n\n## 进一步阅读\n\n- [TodoMVC 示例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [带有键 (keys) 的列表示例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [路由示例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: '字面量和表达式'\n---\n\n## 字面量\n\n如果表达式解析为实现了 `Display` 的类型，它们将被转换为字符串并插入到 DOM 中作为 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 节点。\n\n:::note\n字符串字面量创建 `Text` 节点，浏览器将其视为字符串。因此，即使表达式包含 `<script>` 标签，您也不会遇到 XSS 等安全问题，除非您将表达式包装在 `<script>` 块中。\n:::\n\n所有显示文本都必须用 `{}` 块括起来，因为文本被视为表达式。这是 Yew 与普通 HTML 语法最大的偏差。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 表达式\n\n您可以使用 `{}` 块在 HTML 中插入表达式，只要它们解析为 `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常将这些表达式提取到函数或闭包中以优化可读性是有意义的：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/router.mdx",
    "content": "---\ntitle: '路由 (Router)'\ndescription: 'Yew 的官方路由库'\n---\n\n单页应用程序 (SPA) 中的路由器处理根据 URL 显示不同的页面。与点击链接时请求不同的远程资源的默认行为不同，路由器会在本地设置 URL 以指向应用程序中的有效路由。然后，路由器检测到此更改并决定要渲染的内容。\n\nYew 在 `yew-router` crate 中提供了路由器支持。要开始使用它，请将依赖项添加到您的 `Cargo.toml` 文件中。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n所需的工具均在 `yew_router::prelude` 模块中提供，\n\n## 用法\n\n最开始，你需要定义一个 `Route`。\n\n路由由一个 `enum` 定义，它派生自 `Routable`。这个枚举必须实现 `Clone + PartialEq`。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` 与 `<Switch />` 组件配对，后者会找到与浏览器当前 URL 匹配的路径变体，并将其传递给 `render` 回调。然后回调决定要渲染的内容。如果没有路径匹配，路由器会导航到带有 `not_found` 属性的路径。如果没有指定路由，则不会渲染任何内容，并且会在控制台中记录一条消息，说明没有匹配的路由。\n\nyew-router 的大多数组件，特别是 `<Link />` 和 `<Switch />`，必须是某个 Router 组件（例如 `<BrowserRouter />`）的（深层）子元素。通常在应用程序中只需要一个 Router，通常由最顶层的 `<App />` 组件立即渲染。Router 注册了一个上下文，这是 Links 和 Switches 功能所需的。下面提供了一个示例。\n\n:::caution\n在浏览器环境中使用 `yew-router` 时，强烈推荐使用 `<BrowserRouter />`。您可以在 [API 参考](https://docs.rs/yew-router/) 中找到其他路由器类型。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### 路径段\n\n路由还可以使用动态和命名通配符段从路由中提取信息。然后，您可以在 `<Switch />` 内访问帖子的 id，并通过属性将其转发到相应的组件。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n您也可以使用普通的 `Post` 变体，而不是 `Post {id: String}`。例如，当 `Post` 与另一个路由器一起渲染时，该字段可能是多余的，因为另一个路由器可以匹配并处理路径。有关详细信息，请参阅下面的[嵌套路由器](#nested-router)部分。\n:::\n\n请注意，字段必须实现 `Clone + PartialEq` 作为 `Route` 枚举的一部分。它们还必须实现 `std::fmt::Display` 和 `std::str::FromStr` 以进行序列化和反序列化。整数、浮点数和字符串等原始类型已经满足这些要求。\n\n当路径的形式匹配，但反序列化失败（根据 `FromStr`）时。路由器将认为路由不匹配，并尝试渲染未找到的路由（或者如果未指定未找到的路由，则渲染空白页面）。\n\n参考以下示例：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// 切换函数会渲染 News 和 id。这里省略了。\n```\n\n当段超过 255 时，`u8::from_str()` 将失败并返回 `ParseIntError`，路由器将认为路由不匹配。\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\n有关路由语法和如何绑定参数的更多信息，请查看 [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params)。\n\n### 位置 (Location)\n\n路由器通过上下文提供了一个通用的 `Location` 结构，可以用于访问路由信息。它们可以通过钩子或 `ctx.link()` 上的便捷函数来检索。\n\n### 导航\n\n`yew_router` 提供了一些工具来处理导航。\n\n#### 链接\n\n`<Link />` 渲染为 `<a>` 元素，`onclick` 事件处理程序将调用 [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)，并将目标页面推送到历史记录中并渲染所需的页面，这正是单页应用程序所期望的行为。普通锚元素的默认 `onclick` 会重新加载页面。\n\n`<Link />` 组件还会将其子元素传递给 `<a>` 元素。可以将其视为应用内路由的 `<a/>` 替代品。不同之处在于你需要提供 `to` 属性而不是 `href`。示例用法如下：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n结构体变量也可以正常工作：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### 导航接口\n\n导航器 API 为函数组件和结构组件提供。它们使回调能够更改路由。可以在任一情况下获取 `Navigator` 实例以操作路由。\n\n##### 函数式组件\n\n对于函数组件，当底层导航器提供程序更改时，`use_navigator` 钩子会重新渲染组件。\n以下是实现一个按钮的示例，该按钮在点击时导航到 `Home` 路由。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\n这里的示例使用了 `Callback::from`。如果目标路由可以与组件所在的路由相同，或者只是为了安全起见，请使用普通的回调。例如，考虑在每个页面上都有一个徽标按钮，点击该按钮会返回主页。在主页上点击该按钮两次会导致代码崩溃，因为第二次点击会推送一个相同的 Home 路由，并且 `use_navigator` 钩子不会触发重新渲染。\n:::\n\n如果您想替换当前的位置而不是将新位置推到堆栈上，请使用 `navigator.replace()` 而不是 `navigator.push()`。\n\n您可能会注意到 `navigator` 必须移动到回调中，因此不能再次用于其他回调。幸运的是，`navigator` 实现了 `Clone`，例如，以下是如何为不同的路由设置多个按钮：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 结构体组件\n\n对于结构体组件，可以通过 `ctx.link().navigator()` API 获取 `Navigator` 实例。其余部分与函数组件的情况相同。以下是一个渲染单个按钮的视图函数示例。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### 重定向\n\n`yew-router` 还在 prelude 中提供了一个 `<Redirect />` 组件。它可以用于实现与导航器 API 类似的效果。该组件接受一个 `to` 属性作为目标路由。当渲染 `<Redirect/>` 时，用户将被重定向到属性中指定的路由。以下是一个示例：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // 建立对 `use_user` 的钩子\n    let user = match use_user() {\n        Some(user) => user,\n        // 当用户为 `None` 时重定向到登录页面\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 实际页面内容\n}\n```\n\n:::tip 如何选择 `Redirect` 或 `Navigator`\nNavigator API 是在回调中操作路由的唯一方法。\n而 `<Redirect />` 可以作为组件中的返回值使用。您可能还希望在其他非组件上下文中使用 `<Redirect />`，例如在[嵌套路由器](#nested-router)的 switch 函数中。\n:::\n\n### 监听变化\n\n#### 函数式组件\n\n您可以使用 `use_location` 和 `use_route` 钩子。当提供的值发生变化时，您的组件将重新渲染。\n\n#### 结构体组件\n\n为了响应路由变化，您可以将回调闭包传递给 `ctx.link()` 的 `add_location_listener()` 方法。\n\n:::note\n一旦位置监听器被删除，它将被取消注册。请确保将句柄存储在组件状态中。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // 处理事件\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` 和 `ctx.link().route::<R>()` 也可以用于一次性检索位置和路由。\n\n### 查询参数\n\n#### 在导航时指定查询参数\n\n为了在导航到新路由时指定查询参数，可以使用 `navigator.push_with_query` 或 `navigator.replace_with_query` 函数。它使用 `serde` 将参数序列化为 URL 的查询字符串，因此任何实现了 `Serialize` 的类型都可以传递。最简单的形式是包含字符串对的 `HashMap`。\n\n#### 获取当前路由的查询参数\n\n`location.query` 用于获取查询参数。它使用 `serde` 从 URL 的查询字符串中反序列化参数。\n\n## 嵌套路由器\n\n当应用程序变得更大时，嵌套路由器可能会很有用。考虑以下路由器结构：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\n嵌套的 `SettingsRouter` 处理所有以 `/settings` 开头的 URL。此外，它会将未匹配的 URL 重定向到主 `NotFound` 路由。因此，`/settings/gibberish` 将重定向到 `/404`。\n\n:::caution\n\n请注意，该接口仍在开发中，这样写的方式尚未最终确定\n\n:::\n\n可以使用以下代码实现：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### 基底路径 (Basename)\n\n可以使用 `yew-router` 定义基底路径 (Basename)。\n基底路径是所有路由的公共前缀。导航器 API 和 `<Switch />` 组件都支持基底路径设置。所有推送的路由都会加上基底路径前缀，所有的 switch 都会在尝试将路径解析为 `Routable` 之前去掉基底路径。\n\n如果没有为 Router 组件提供基底路径属性，它将使用 HTML 文件中 `<base />` 元素的 href 属性，并在 HTML 文件中没有 `<base />` 元素时回退到 `/`。\n\n## 相关示例\n\n- [路由](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## 接口参考\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/suspense.mdx",
    "content": "---\ntitle: '占位标签 (Suspense)'\ndescription: '用于数据获取的占位标签'\n---\n\n占位标签 (Suspense) 是一种在等待任务完成前暂停组件渲染的方式，同时显示一个回退（占位符）UI。\n\n它可以用于从服务器获取数据，等待代理完成任务，或执行其他后台异步任务。\n\n在占位标签出现之前，数据获取通常发生在组件渲染之后（渲染时获取）或之前（获取后渲染）。\n\n### 边渲染，边下载\n\n占位标签 (Suspense) 提供了一种新的方法，允许组件在渲染过程中发起数据请求。当组件发起数据请求时，渲染过程将被暂停，并显示一个回退 UI，直到请求完成。\n\n推荐使用钩子 (Hook) 来使用占位标签。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n在上面的示例中，`use_user` 钩子将在加载用户信息时暂停组件渲染，并在加载 `user` 之前显示 `Loading...` 占位符。\n\n要定义一个暂停组件渲染的钩子，它需要返回一个 `SuspensionResult<T>`。当组件需要被暂停时，钩子应该返回一个 `Err(Suspension)`，用户应该使用 `?` 解包它，这样它将被转换为 `Html`。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 当用户加载完成时，我们将其作为 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 当用户仍在加载时，我们创建一个 `Suspension`\n            // 并在数据加载完成时调用 `SuspensionHandle::resume`，\n            // 组件将自动重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### 关于实现暂停钩子 (Hook) 的注意事项\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) 返回 2 个值：暂停上下文本身和一个暂停句柄。后者负责在何时重新渲染暂停的组件，它提供了 2 种可互换的方法：\n\n1. 调用其 [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) 方法。\n2. 丢弃句柄。\n\n:::danger\n\n暂停句柄必须存储直到更新组件的时候，即使用新接收的数据；否则，暂停的组件将进入无限重新渲染循环，从而影响性能。\n在上面的示例中，暂停句柄通过移动到闭包中并传递给 `on_load_user_complete` 来保存。\n当虚拟用户加载时，将调用闭包，从而调用 `handle.resume()` 并重新渲染与暂停上下文相关的组件。\n\n:::\n\n# 完整示例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 如果用户已加载，则将其作为 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 当用户仍在加载时，我们创建一个 `Suspension`\n            // 并在数据加载完成时调用 `SuspensionHandle::resume`，\n            // 组件将自动重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 在结构体组件中使用占位标签\n\n直接暂停结构体组件是不可能的。然而，您可以使用一个函数组件作为[高阶组件](../advanced-topics/struct-components/hoc)来实现基于占位标签的数据获取。\n\nYew 仓库中的[占位标签示例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)演示了如何使用这个组件。\n\n## 相关示例\n\n- [占位标签](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: '构建一个示例应用'\n---\n\n当您的环境准备好后，您可以选择使用一个包含基本 Yew 应用所需样板的起始模板，或手动设置一个小项目。\n\n## 使用模板快速起步\n\n按照 [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) 的安装说明安装该工具，然后运行以下命令：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手动配置应用\n\n### 创建项目\n\n首先，请创建一个新的 cargo 项目。\n\n```bash\ncargo new yew-app\n```\n\n打开新创建的目录。\n\n```bash\ncd yew-app\n```\n\n### 运行一个 hello world 示例\n\n为了验证 Rust 环境是否设置正确，使用 `cargo run` 运行初始项目。您应该看到一个 \"Hello World!\" 消息。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### 将项目设置为 Yew web 应用\n\n为了将这个简单的命令行应用程序转换为一个基本的 Yew web 应用程序，需要进行一些更改。\n\n#### 更新 Cargo.toml\n\n将 `yew` 添加到依赖列表中。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n# 开发版本的 Yew\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在构建一个应用程序，你只需要 `csr` 特性。它将启用 `Renderer` 和所有与客户端渲染相关的代码。\n\n如果你正在制作一个库，请不要启用此特性，因为它会将客户端渲染逻辑拉入服务器端渲染包中。\n\n如果你需要 Renderer 进行测试或示例，你应该在 `dev-dependencies` 中启用它。\n\n:::\n\n#### 更新 main.rs\n\n我们需要生成一个模板，设置一个名为 `App` 的根组件，该组件渲染一个按钮，当点击时更新其值。用以下代码替换 `src/main.rs` 的内容。\n\n:::note\n`main` 函数中的 `yew::Renderer::<App>::new().render()` 调用启动您的应用程序并将其挂载到页面的 `<body>` 标签上。如果您想要使用任何动态属性启动您的应用程序，您可以使用 `yew::Renderer::<App>::with_props(..).render()`。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### 创建 index.html\n\n最后，在应用程序的根目录中添加一个 `index.html` 文件。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## 查看您的 Web 应用\n\n运行以下命令在本地构建和提供应用程序。\n\n```bash\ntrunk serve\n```\n\n:::info\n添加选项 '--open' 来打开您的默认浏览器 `trunk serve --open`。\n:::\n\nTrunk 将在您修改任何源代码文件时实时重新构建您的应用程序。\n默认情况下，服务器将在地址 '127.0.0.1' 的端口 '8080' 上监听 => [http://localhost:8080](http://127.0.0.1:8080)。\n要更改这部分配置，请创建以下文件并根据需要进行编辑：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 局域网上的监听地址\naddress = \"127.0.0.1\"\n# 广域网上的监听地址\n# address = \"0.0.0.0\"\n# 监听的端口\nport = 8000\n```\n\n## 恭喜\n\n您现在已经成功设置了您的 Yew 开发环境，并构建了您的第一个 Web 应用程序。\n\n尝试这个应用程序，并查看[示例](./examples.mdx)以进一步学习。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/getting-started/editor-setup.mdx",
    "content": "---\ntitle: '设置编辑器'\ndescription: '设置您的代码编辑器'\n---\n\n:::important 改进文档\n有在使用不同的编辑器？如有推荐，请随意添加您选择的编辑器的说明。\n:::\n\n## 为创建组件添加模板\n\n### JetBrains IDEs\n\n1. 从导航栏依次点击 File | Settings | Editor | Live Templates.\n2. 选择 Rust 并点击 + 图标添加新的 Live Template。\n3. 根据需要给它一个的名称和描述。\n4. 将以下代码片段粘贴到模板文本部分。\n5. 在右下角更改适用性，选择 Rust > Item > Module\n\n对于函数式组件，使用以下模板。\n\n- (可选) 点击编辑变量，并给 `tag` 一个合理的默认值，例如 \"div\"，用双引号。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n对于结构体组件，可以使用以下更复杂的模板。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. 从导航栏依次点击 File > Preferences > User Snippets.\n2. 选择 Rust 作为设置语言。\n3. 在 JSON 文件中添加以下代码片段：\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## 支持 `html!` 宏\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 扩展\n\n> 这是一个**正在进行中**的，**由社区维护**的项目！[请查看详细信息，并将相关的 bug 报告/问题/疑问直接发送到扩展的存储库](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 扩展 [可以在 VSC Marketplace 上找到](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)，提供语法高亮、重命名、悬停等功能。\n\nEmmet 支持应该可以直接使用，如果不能，请回退到编辑 `settings.json` 文件：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> 下面的配置适用于 [LazyVim](https://www.lazyvim.org) 配置和 lazy.vim 插件，请在 `lua/plugins/nvim-lspconfig.lua` 中创建一个文件（或更新您的 `lspconfig`）：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/getting-started/examples.mdx",
    "content": "---\ntitle: '示例'\n---\n\nYew 仓库包含许多[示例]（维护状态各异）。\n我们建议浏览它们以了解如何使用框架的不同功能。\n我们也欢迎拉取请求和问题，以便在它们不可避免地被忽略并需要一些帮助 ♥️ 时使用。\n\n有关更多详细信息，包括示例列表，请参阅[README]。\n\n:::note\n大多数示例都有一个可以在 https://examples.yew.rs/< example_name > 找到的在线部署。\n在各自的子文件夹中的 README 页面上点击它们的徽章以导航到在线演示。\n:::\n\n[示例列表]: https://github.com/yewstack/yew/tree/master/examples\n[示例文档 README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/getting-started/introduction.mdx",
    "content": "---\ntitle: '开始使用'\n---\n\n你需要一些工具来编译、构建、打包和调试你的 Yew 应用程序。在最开始，我们建议使用 [Trunk](https://trunkrs.dev/)。Trunk 是一个用于 Rust 的 WASM Web 应用程序打包工具。\n\n## 安装 Rust\n\n要安装 Rust，请按照[官方说明](https://www.rust-lang.org/tools/install)。\n\n:::important\nYew 支持的最低 Rust 版本（MSRV）是 `1.84.0`。旧版本将无法编译。您可以使用 `rustup show`（在“active toolchain”下）或 `rustc --version` 检查您的工具链版本。要更新您的工具链，请运行 `rustup update`。\n:::\n\n## 安装 WebAssembly 目标\n\nRust 可以为不同的“目标”（例如不同的处理器）编译源代码。用于基于浏览器的 WebAssembly 的编译目标称为 `wasm32-unknown-unknown`。以下命令将向您的开发环境添加 WebAssembly 目标。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## 安装 Trunk\n\nTrunk 是推荐的用于管理部署和打包的工具，并在整个文档和示例中使用。\n\n```shell\n# 需要注意的是，这可能需要一段时间来安装，因为它会从头开始编译所有内容\n# Trunk 还为许多主要的包管理器提供了预构建的二进制文件\n# 有关更多详细信息，请参见 https://trunkrs.dev/#install\ncargo install --locked trunk\n```\n\n### 其他选项\n\n除了 Trunk 之外，还有其他选项可用于打包 Yew 应用程序。您可能想尝试以下选项之一：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (仍在早期开发阶段)\n\n## 下一步\n\n设置好开发环境后，您现在可以继续阅读文档。如果您喜欢通过动手实践来学习，我们建议您查看我们的[教程](../tutorial)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: '从 0.22.0 迁移到 0.23.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` 不再在恒等分发时重新渲染\n\n`use_reducer` 现在在 reducer 返回相同的 `Rc` 时（通过指针相等性判断）会跳过重新渲染。之前，每次分发都会触发重新渲染。\n\n如果你的 reducer 有一个返回 `self` 不变的代码路径，并且你依赖它来触发重新渲染，请用 `use_force_update` 替代：\n\n<Tabs>\n  <TabItem value=\"before\" label=\"之前\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // 在 0.23 中这不再触发重新渲染！\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"刷新\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"之后\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"刷新\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: '从 0.4.0 迁移到 0.5.0'\n---\n\n没有破坏性变更。在 `Cargo.toml` 中将 yew-agent 更新到 0.5.0。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: '从 0.19.0 迁移到 0.20.0'\n---\n\n没有破坏性变更。在 `Cargo.toml` 中将 yew-router 更新到 0.20.0。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\n一个关于如何最好地将 CSS 支持集成到 Yew 中的讨论可以在这里找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n这里包含了很多关于如何最好地将 CSS 支持集成到 Yew 中的讨论。\n\n目前，我们采用的方法是鼓励开发者在采用最流行的系统之前构建许多系统。\n\n社区目前正在开发几个项目，以便为项目添加样式。以下是其中的一些：\n\n#### 组件库\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - 一个没有任何 JavaScript 依赖的 Yew 样式框架。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design 组件。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS 组件。\n- [Yewtify](https://github.com/yewstack/yewtify) – 在 Yew 中实现 Vuetify 框架提供的功能。\n\n#### 样式解决方案\n\n- [stylist](https://github.com/futursolo/stylist-rs) - 用于 WebAssembly 应用程序的 CSS-in-Rust 样式解决方案。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind 实用类。\n\n:::important 改进文档\n如果您正在开发一个为 Yew 添加样式的项目，请提交一个 PR 将自己添加到这个列表中！\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/more/debugging.mdx",
    "content": "---\ntitle: '调试'\n---\n\n## 意外终止 (Panics)\n\nYew 会自动在浏览器控制台中输出意外终止日志。\n\n## 控制台日志\n\n在 JavaScript 中，`console.log()` 用于输出到浏览器控制台。以下是一些 Yew 的选项。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate 与 [`log`](https://crates.io/crates/log) crate 集成，以将日志级别、源行和文件名发送到浏览器控制台。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\n这个 crate 是 Gloo 的一部分，提供了对浏览器 API 的 Rust 包装。`log!` 宏可以直接接受 `JsValue`，比 `wasm_logger` 更容易使用。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` 可以与 [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) 一起使用，将消息输出到浏览器控制台。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## 调试组件生命周期\n\n[`tracing`](https://crates.io/crates/tracing) 可以用于收集与组件生命周期相关的事件信息。`tracing` 还带有一个 `log` 支持的特性标志，可以与 `wasm-logger` 很好地集成。\n\n[编译时过滤器](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) 可以用于调整详细程度或禁用日志记录，这应该会导致更小的 Wasm 文件。\n\n## 源映射 (Source Maps)\n\n有一些支持 [源映射](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf)。但是，需要一些配置。\n\n## 过去的文章\n\n以下是一些关于 Rust 中 WebAssembly 调试状态的过去文章。它们可能是有趣的阅读。\n\n\\[Dec 2019\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 这些工作还有很多要做。例如，在工具方面，Emscripten（Binaryen）和 wasm-pack（wasm-bindgen）尚未支持在它们执行的转换上更新 DWARF 信息。\n\n\\[2020\\] [Rust Wasm 调试指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸的是，WebAssembly 的调试能力仍然不成熟。在大多数 Unix 系统上，[DWARF](http://dwarfstd.org/) 用于编码调试器需要提供运行中程序的源级检查的信息，就连在 Windows 上有一种编码类似信息的替代格式。但目前，WebAssembly 没有相应的格式。\n\n\\[2019\\] [Rust Wasm 路线图](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 调试很棘手，因为很多情况不在这个工作组的掌控之中，而是取决于 WebAssembly 标准化机构和实现浏览器开发者工具的人。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/more/deployment.mdx",
    "content": "---\ntitle: '部署'\ndescription: '部署 Yew 应用程序'\n---\n\n当您准备将 Yew 应用程序部署到服务器时，您有多种部署方案可以选择。\n\n`trunk build --release` 会以发布模式构建您的应用程序。设置您的 HTTP 服务器，以便在访问您的站点时提供 `index.html`，并且对于静态路径（例如 `index_<hash>.js` 和 `index_bg_<hash>.wasm`）的请求，应该从 trunk 生成的 dist 目录中提供相应的内容。\n\n:::important 有关 `trunk serve --release`\n不要在生产环境中使用 `trunk serve --release` 来提供您的应用程序。\n它只应该用于在开发过程中测试发布版本构建。\n:::\n\n## 服务器配置\n\n### 将 `index.html` 作为回退提供\n\n如果应用程序使用了 [Yew 路由](concepts/router.mdx)，您必须配置服务器在请求不存在的文件时返回 `index.html`。\n\n具有 Yew 路由的应用程序被构建为 [单页应用程序 (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA)。当用户从正在运行的客户端导航到 URL 时，路由器会解释 URL 并路由到该页面。\n\n但是在刷新页面或在地址栏中输入 URL 时，这些操作都是由浏览器本身处理的，而不是由正在运行的应用程序处理。浏览器直接向服务器请求该 URL，绕过了路由器。错误配置的服务器会返回 404 - 未找到 状态。\n\n通过返回 `index.html`，应用程序会像通常一样加载，就好像请求是 `/`，直到路由器注意到路由是 `/show/42` 并显示相应的内容。\n\n### 为 Web Assembly 资源配置正确的 MIME 类型。\n\nWASM 文件必须使用 `application/wasm` MIME 类型设置 [Content-Type 头](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。\n\n大多数服务器和托管服务默认已经这样做。如果您的服务器没有这样做，请查阅其文档。在大多数 Web 浏览器中，错误的 MIME 类型会导致类似以下的错误：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 为相对路径构建\n\n默认情况下，trunk 会假定您的站点在 `/` 处提供，并相应地构建站点。可以通过在 `index.html` 文件中添加 `<base data-trunk-public-url />` 来覆盖此行为。Trunk 会重写此标签以包含传递给 `--public-url` 的值。Yew 路由会自动检测 `<base />` 的存在并适当处理。\n\n## 使用环境变量自定义行为\n\n通常使用环境变量来自定义构建环境。由于应用程序在浏览器中运行，我们无法在运行时读取环境变量。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) 宏可以在编译时获取环境变量的值。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/more/roadmap.mdx",
    "content": "---\ntitle: '路线图'\ndescription: 'Yew 框架的计划功能路线图'\n---\n\n## 优先级\n\n框架即将推出的功能和重点的优先级由社区决定。\n在 2020 年春季，我们发送了一份开发者调查，以收集关于项目方向的反馈。\n您可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到调查摘要。\n\n:::note\n所有主要倡议的状态都可以在 Yew Github [项目看板](https://github.com/yewstack/yew/projects) 上跟踪\n:::\n\n## 重点\n\n1. 最受欢迎的功能\n2. 生产就绪\n3. 文档\n4. 痛点\n\n### 最受欢迎的功能\n\n1. [函数组件](https://github.com/yewstack/yew/projects/3)\n2. [组件库](https://github.com/yewstack/yew/projects/4)\n3. 更好的状态管理\n4. [服务器端渲染](https://github.com/yewstack/yew/projects/5)\n\n### 生产就绪所需的问题\n\n- 提高 Yew 测试覆盖率\n- 减小二进制文件大小\n- [性能基准测试](https://github.com/yewstack/yew/issues/5)\n\n### 文档\n\n- 创建教程\n- 简化项目设置\n\n### 痛点\n\n- [组件样板](https://github.com/yewstack/yew/issues/830)\n- [代理](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/more/testing.mdx",
    "content": "---\ntitle: '测试应用'\ndescription: '测试你的应用'\n---\n\n:::info\n我们正在努力让测试组件变得更容易，但目前仍在进行中。\n\n在 GitHub 仓库中可以找到对 [浅渲染](https://github.com/yewstack/yew/issues/1413) 的支持。\n:::\n\n## 快照测试\n\nYew 提供了 `yew::tests::layout_tests` 模块来方便组件的快照测试。\n\n:::important 改进文档\n我们需要帮助，以改进快照测试的文档。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM 工作组维护了一个叫做 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) 的 crate，\n它允许你以类似于内置的 `#[test]` 过程宏的方式在浏览器中运行测试。\n有关此模块的更多信息，请参阅 [Rust Wasm 工作组的文档](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/tutorial/index.mdx",
    "content": "---\ntitle: '教程'\nslug: /tutorial\n---\n\n## 介绍\n\n在这个实践教程中，我们将学习如何使用 Yew 构建 Web 应用程序。\n**Yew** 是一个现代的 [Rust](https://www.rust-lang.org/) 框架，用于使用 [WebAssembly](https://webassembly.org/) 构建前端 Web 应用程序。\nYew 通过利用 Rust 强大的类型系统，鼓励可重用、可维护和良好结构化的架构。\n一个庞大的社区创建的库生态系统，称为 Rust 中的 [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)，为常用模式（如状态管理）提供了组件。\nRust 的包管理器 [Cargo](https://doc.rust-lang.org/cargo/) 允许我们利用 [crates.io](https://crates.io) 上提供的大量 crate，例如 Yew。\n\n### 我们将要构建的内容\n\nRustconf 是 Rust 社区每年举办的星际聚会。\nRustconf 2020 有大量的演讲，提供了大量的信息。\n在这个实践教程中，我们将构建一个 Web 应用程序，帮助其他 Rustaceans 了解这些演讲并从一个页面观看它们。\n\n## 设置\n\n### 先决条件\n\n这个教程假设您已经熟悉 Rust。如果您是 Rust 的新手，免费的 [Rust 书](https://doc.rust-lang.org/book/ch00-00-introduction.html) 为初学者提供了一个很好的起点，并且即使对于有经验的 Rust 开发人员来说，它仍然是一个很好的资源。\n\n确保安装了最新版本的 Rust，方法是运行 `rustup update` 或者[安装 Rust](https://www.rust-lang.org/tools/install)。\n\n安装 Rust 后，您可以使用 Cargo 运行以下命令安装 `trunk`：\n\n```bash\ncargo install trunk\n```\n\n我们还需要添加 WASM 构建目标，运行以下命令：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### 设置项目\n\n首先，创建一个新的 cargo 项目：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\n为了验证 Rust 环境是否设置正确，使用 cargo 构建工具运行初始项目。\n在关于构建过程的输出之后，您应该看到预期的 \"Hello, world!\" 消息。\n\n```bash\ncargo run\n```\n\n## 我们的第一个静态页面\n\n为了将这个简单的命令行应用程序转换为一个基本的 Yew web 应用程序，需要进行一些更改。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在构建一个应用程序，你只需要 `csr` 特性。它将启用 `Renderer` 和所有与客户端渲染相关的代码。\n\n如果你正在制作一个库，请不要启用此特性，因为它会将客户端渲染逻辑拉入服务器端渲染包中。\n\n如果你需要 Renderer 进行测试或示例，你应该在 `dev-dependencies` 中启用它。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n现在，让我们在项目的根目录创建一个 `index.html`。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 启动开发服务器\n\n运行以下命令构建并在本地提供应用程序。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n删除选项 '--open' 以在运行 `trunk serve` 后不打开默认浏览器。\n:::\n\nTrunk 将在您修改任何源代码文件时实时重新构建您的应用程序。\n默认情况下，服务器将在地址 '127.0.0.1' 的端口 '8080' 上监听 => [http://localhost:8080](http://127.0.0.1:8080)。\n要更改这部分配置，请创建以下文件并根据需要进行编辑：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 局域网上的监听地址\naddress = \"127.0.0.1\"\n# 广域网上的监听地址\n# address = \"0.0.0.0\"\n# 监听的端口\nport = 8000\n```\n\n如果您感兴趣，您可以运行 `trunk help` 和 `trunk help <subcommand>` 以获取更多关于正在进行的流程的详细信息。\n\n### 恭喜\n\n您现在已经成功设置了 Yew 开发环境，并构建了您的第一个 Yew Web 应用程序。\n\n## 构建 HTML\n\nYew 利用了 Rust 的过程宏，并为我们提供了一种类似于 JSX（JavaScript 的扩展，允许您在 JavaScript 中编写类似 HTML 的代码）的语法来创建标记。\n\n### 转换为经典 HTML\n\n由于我们已经对我们的网站长什么样有了一个很好的想法，我们可以简单地将我们的草稿转换为与 `html!` 兼容的表示。如果您习惯于编写简单的 HTML，那么您在 `html!` 中编写标记时应该没有问题。需要注意的是，这个宏与 HTML 有一些不同之处：\n\n1. 表达式必须用大括号（`{ }`）括起来\n2. 只能有一个根节点。如果您想要在不将它们包装在容器中的情况下拥有多个元素，可以使用空标签/片段（`<> ... </>`）\n3. 元素必须正确关闭。\n\n我们想要构建一个布局，原始 HTML 如下：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\n现在，让我们将这个 HTML 转换为 `html!`。将以下代码片段输入（或复制/粘贴）到 `app` 函数的主体中，以便函数返回 `html!` 的值\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\n刷新浏览器页面，您应该看到以下输出：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### 在标记中使用 Rust 语言结构\n\n在 Rust 中编写标记的一个很大的优势是，我们在标记中获得了 Rust 的所有优点。\n现在，我们不再在 HTML 中硬编码视频列表，而是将它们定义为 `Vec` 的 `Video` 结构体。\n我们创建一个简单的 `struct`（在 `main.rs` 或我们选择的任何文件中）来保存我们的数据。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n接下来，我们将在 `app` 函数中创建这个结构体的实例，并使用它们来替代硬编码的数据：\n\n```rust\nuse website_test::tutorial::Video; // 换成你自己的路径\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\n为了显示它们，我们需要将 `Vec` 转换为 `Html`。我们可以通过创建一个迭代器，将其映射到 `html!` 并将其收集为 `Html` 来实现：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\n在列表项上使用键有助于 Yew 跟踪列表中哪些项发生了变化，从而实现更快的重新渲染。[始终建议在列表中使用键](/concepts/html/lists.mdx#keyed-lists)。\n:::\n\n最后，我们需要用从数据创建的 `Html` 替换硬编码的视频列表：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## 组件\n\n组件是 Yew 应用程序的构建块。通过组合组件（可以由其他组件组成），我们构建我们的应用程序。通过为可重用性构建组件并保持它们的通用性，我们将能够在应用程序的多个部分中使用它们，而无需重复代码或逻辑。\n\n到目前为止我们一直在使用的 `app` 函数是一个组件，称为 `App`。它是一个“函数式组件”。\n\n1. 结构体组件\n2. 函数式组件\n\n在本教程中，我们将使用函数式组件。\n\n现在，让我们将 `App` 组件拆分为更小的组件。我们首先将视频列表提取到自己的组件中。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n注意我们的 `VideosList` 函数组件的参数。函数组件只接受一个参数，该参数定义了它的 \"props\"（\"properties\" 的缩写）。Props 用于从父组件传递数据到子组件。在这种情况下，`VideosListProps` 是一个定义 props 的结构体。\n\n:::important\n用于 props 的结构体必须通过派生实现 `Properties`。\n:::\n\n为了使上面的代码编译通过，我们需要修改 `Video` 结构体如下：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n现在，我们可以更新我们的 `App` 组件以使用 `VideosList` 组件。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n通过查看浏览器窗口，我们可以验证列表是否按预期呈现。我们已经将列表的渲染逻辑移动到了它的组件中。这缩短了 `App` 组件的源代码，使我们更容易阅读和理解。\n\n### 使应用可以交互\n\n这里的最终目标是显示所选视频。为了做到这一点，`VideosList` 组件需要在选择视频时“通知”其父组件，这是通过 `Callback` 完成的。这个概念称为“传递处理程序”。我们修改其 props 以接受一个 `on_click` 回调：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n然后我们修改 `VideosList` 组件以将所选视频传递给回调。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n接下来，我们需要修改 `VideosList` 的使用以传递该回调。但在这样做之前，我们应该创建一个新的组件 `VideoDetails`，当点击视频时才会显示。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n现在，修改 `App` 组件以在选择视频时显示 `VideoDetails` 组件。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n现在不用担心 `use_state`，我们稍后会回到这个问题。注意我们用 `{ for details }` 提取列表数据的技巧。\n`Option<_>` 实现了 `Iterator`，所以我们可以使用特殊的 `{ for ... }` 语法来逐个显示 `Iterator` 返回的唯一元素，而这[由 `html!` 宏支持](concepts/html/lists)。\n\n### 处理状态\n\n还记得之前使用的 `use_state` 吗？那是一个特殊的函数，称为 \"hook\"。Hooks 用于 \"hook\" 到函数组件的生命周期中并执行操作。您可以在[这里](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)了解更多关于这个 hook 和其他 hook 的信息。\n\n:::note\n结构体组件的行为不同。请查看[文档](advanced-topics/struct-components/introduction.mdx)了解有关这些的信息。\n:::\n\n## 获取数据（使用外部 REST API）\n\n在真实的应用程序中，数据通常来自 API 而不是硬编码。让我们从外部源获取我们的视频列表。为此，我们需要添加以下 crate：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  用于进行 fetch 调用。\n- [`serde`](https://serde.rs) 和其派生特性\n  用于反序列化 JSON 响应\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  用于将 Rust 的 Future 作为 Promise 执行\n\n让我们更新 `Cargo.toml` 文件中的依赖项：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n在选择依赖项时，请确保它们与 `wasm32` 兼容！否则，您将无法运行您的应用程序。\n:::\n\n更新 `Video` 结构体以派生 `Deserialize` 特性：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n作为最后一步，我们需要更新我们的 `App` 组件，以便进行 fetch 请求，而不是使用硬编码的数据\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\n我们在这里使用 `unwrap`，因为这是一个演示应用程序。在真实的应用程序中，您可能希望有[适当的错误处理](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)。\n:::\n\n现在，查看浏览器，看看一切是否按预期工作……如果不是因为 CORS 的话。为了解决这个问题，我们需要一个代理服务器。幸运的是 trunk 提供了这个功能。\n\n更新这些行：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n现在，使用以下命令重新运行服务器：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\n刷新网页，一切应该按预期工作。\n\n## 总结\n\n恭喜！您已经创建了一个从外部 API 获取数据并显示视频列表的 Web 应用程序。\n\n## 接下来\n\n这个应用程序离完美或有用还有很长的路要走。在完成本教程后，您可以将其作为探索更高级主题的起点。\n\n### 样式\n\n我们的应用程序看起来非常丑陋。没有 CSS 或任何样式。不幸的是，Yew 没有提供内置的样式组件。请查看 [Trunk 的 assets](https://trunkrs.dev/assets/)，了解如何添加样式表。\n\n### 更多依赖库\n\n我们的应用程序只使用了很少的外部依赖。有很多 crate 可以使用。请查看[外部库](/community/external-libs)以获取更多详细信息。\n\n### 了解更多关于 Yew\n\n阅读我们的[官方文档](../getting-started/introduction.mdx)。它更详细地解释了许多概念。要了解有关 Yew API 的更多信息，请查看我们的[API 文档](https://docs.rs/yew)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/current.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"从零开始\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"核心概念\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew 核心概念\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"了解 Yew 的重要概念！\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"函数式组件\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"高级主题\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"高级主题\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"了解 Yew 的更多内部细节！\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"更多\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"杂项\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"迁移指南\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Yew 中的基本 Web 技术\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew 对基本 Web 技术的看法\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew 主要基于将可重用的 UI 部件所需的所有内容放在一个地方 - rust 文件的想法。但也力求保持与技术的原始外观接近。进一步探索，以充分理解我们对这些陈述的含义：\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"钩子\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"结构化组件\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/advanced-topics/how-it-works.mdx",
    "content": "---\ndescription: 有关框架的底层细节\n---\n\n# 底层库的内部细节\n\n组件生命周期状态机，虚拟 dom diff 算法。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/advanced-topics/optimizations.mdx",
    "content": "---\ndescription: 加速你的应用程序\n---\n\n# 性能优化与最佳实践\n\n## neq_assign\n\n当组件从它的父组件接收 props 时，`change` 方法将被调用。除了允许你更新组件的状态，还允许你返回一个布尔类型的值 `ShouldRender` 来指示组件是否应该响应 props 的更改而重新渲染自身。\n\n重新渲染的开销很大，你应该尽量避免。一个通用的法则是，你只应该在 props 实际更改时重新渲染。以下代码块展示了此法则，如果 props 和先前的 props 不同，则返回 `true`：\n\n```rust\nfn change(&mut self, props: Self::Properties) -> ShouldRender {\n    if self.props != &props {\n        *self.props = props;\n        true\n    } else {\n        false\n    }\n}\n```\n\n但是我们可以更进一步！对于任何实现了 `PartialEq` 的项，可以使用一个 trait 和一个 blanket implementation 将这六行样板代码减少到一行。\n\n```rust title=\"neq_assign.rs\"\npub trait NeqAssign {\n    fn neq_assign(&mut self, new: Self) -> ShouldRender;\n}\nimpl<T: PartialEq> NeqAssign for T {\n    fn neq_assign(&mut self, new: T) -> ShouldRender {\n        if self != &new {\n            *self = new;\n            true\n        } else {\n            false\n        }\n    }\n}\n\n// ...\nfn change(&mut self, props: Self::Properties) -> ShouldRender {\n    self.props.neq_assign(props)\n}\n```\n\n该 trait 称为 `NeqAssign` 是因为如果目标值和新值不相等，它将赋为新值。\n\n这比简单的实现还要短：\n\n```rust\n// 不要这样做，除非你无法避免。\nfn change(&mut self, props: Self::Properties) -> ShouldRender {\n    self.props = props;\n    true\n}\n```\n\n你不仅限在 `change` 函数中使用它。通常，在 `update` 函数中执行此操作也是有意义的，尽管性能提升在那里不太明显。\n\n## RC\n\n为了避免在重新渲染时为了创建 props 而克隆大块数据，我们可以使用智能指针来只克隆指针。如果在 props 和子组件中使用 `Rc<_>` 而不是普通未装箱的值，则可以延迟克隆直到需要修改子组件中的数据为止，在该组件中可以使用 `Rc::make_mut` 来对要更改数据进行克隆和获取可变引用。通过在要修改前不进行克隆，子组件可以在几乎没有性能成本的情况下拒绝与它们在 `Component::change` 中拥有状态的 props 相同的 props，这与数据本身需要先复制到父级 props 结构体中，然后在子级中进行比较和拒绝的情况相反。\n\n对于不是 `Copy` 类型的数据，这种优化是最有用的。如果你能轻松地拷贝数据，那么将其放入智能指针中可能是不值得的。对于可以包含大量数据的结构，例如 `Vec`，`HashMap` 和 `String`，这种优化应该是值得的。\n\n如果子组件从不更新组件的值，则这种优化效果最好，如果父组件很少更新组件的值，则效果更好。这使得 `Rc<_>s` 是包装纯组件属性值的不错选择。\n\n## 视图函数\n\n出于代码可读性的原因，将 `html!` 各个部分的代码迁移到他们自己的函数中通常是有意义的，这样就可以避免在深层嵌套的 HTML 中出现代码块向右偏移。\n\n## 纯组件 / 函数式组件\n\n纯组件是不会修改它们状态的组件，它们仅展示内容和向普通可变组件传递消息。它们与视图函数不同之处在于他们可以使用组件语法（`<SomePureComponent />`）而不是表达式语法（`{some_view_function()}`）来在 `html!` 宏中使用，并且根据它们的实现，它们可以被记忆化 - 使用前面提到的 `neq_assign` 逻辑来防止因为相同的 props 而重新渲染。\n\nYew 没有原生支持纯组件或者函数式组件，但是可以通过外部库获取它们。\n\n函数式组件尚不存在，但是从理论上来讲，可以通过使用 proc 宏和标注函数生成纯组件。\n\n## Keyed DOM nodes when they arrive\n\n## 使用 Cargo Workspaces 进行编译速度优化\n\n可以说，使用 Yew 的最大缺点是编译时间长。编译时间似乎与 `html!` 宏块中的代码量相关。对于较小的项目，这通常不是什么大问题，但是对于跨多个页面的 web 应用程序，将代码拆分为多个 crates 以最大程度地减少编译器要做的工作通常是有意义的。\n\n你应该尝试让主 crate 处理路由和页面选择，将所有公用的代码移动到另一个 crate，然后为每一个页面创建一个不同的 crate，其中每个页面可能是一个不同的组件，或者只是一个产生 `Html` 的大函数。在最好的情况下，你将从重新构建所有代码到只重新构建主 crate 和一个页面的 crate。在最糟糕的情况下，当你在“公共” crate 中编辑内容时，你将回到起点：编译所有依赖此公用 crate 的代码，这可能就是除此之外的所有代码。\n\n如果你的主 crate 过于庞大，或者你想在深层嵌套的页面（例如，在另一个页面顶部渲染的页面）中快速迭代，则可以使用一个示例 crate 创建一个更简单的主页面实现并在之上渲染你正在开发的组件。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ndescription: ComponentLink 和 Callbacks.\n---\n\n# 回调（Callbacks）\n\n组件“link”是一种机制，通过该机制，组件可以注册回调并自行更新。\n\n## ComponentLink API\n\n### callback\n\n注册一个回调，该回调将在执行时将消息发送到组件的更新机制。在内部，它将使用提供的闭包返回的消息调用 `send_self`。提供 `Fn(IN) -> Vec<COMP::Message>`，返回 `Callback<IN>`。\n\n### send_message\n\n当前循环结束后立即向组件发送消息，导致另一个更新循环启动。\n\n### send_message_batch\n\n注册一个回调，该回调在执行时立即发送一批消息。如果其中任何一个消息将导致组件重新渲染，那么组件会在该批次所有消息被处理后重新渲染。提供 `Fn(IN) -> COMP::Message`，返回 `Callback<IN>`。\n\n## Callbacks\n\nCallbacks 用于与 Yew 中的 services，agents 和父组件进行通信。它们仅仅是个 `Fn`，并由 `Rc` 包裹以允许被克隆。\n\n它们有一个 `emit` 函数，该函数将它的 `<IN>` 类型作为参数并将其转换为目标所期望的消息。如果一个回调从父组件中通过 props 提供给子组件，则子组件可以在其 `update` 生命周期钩子中对该回调调用 `emit`，以将消息发送回父组件。在 `html!` 宏内被提供作为 props 的闭包或函数会自动转换为 Callbacks。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ndescription: 组件及其生命周期钩子\n---\n\n# 组件（Components）\n\n## 组件是什么？\n\n组件是 Yew 的基石。它们管理自己的状态，并可以渲染为 DOM。组件是通过实现描述组件生命周期的 `Component` trait 来创建的。\n\n## 生命周期\n\n:::note\n`为我们的文档做出贡献：`[添加组件的生命周期图示](https://github.com/yewstack/docs/issues/22)\n:::\n\n## 生命周期方法\n\n### Create\n\n当一个组件被创建时，它会从其父组件以及一个 `ComponentLink` 接收属性（properties）。属性（properties）可用于初始化组件的状态，“link”可用于注册回调或向组件发送消息。\n\n通常将 props 和 link 存储在组件的结构体中，如下所示：\n\n```rust\npub struct MyComponent {\n    props: Props,\n    link: ComponentLink<Self>,\n}\n\nimpl Component for MyComponent {\n    type Properties = Props;\n    // ...\n\n    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { props, link }\n    }\n\n    // ...\n}\n```\n\n### View\n\n组件在 `view()` 方法中声明它的布局。Yew 提供了 `html!` 宏来声明 HTML 和 SVG 节点和它们的监听器及其子组件。这个宏的行为很像 React 中的 JSX，但是使用的是 Rust 表达式而不是 JavaScript。\n\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        let onclick = self.link.callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ self.props.button_text }</button>\n        }\n    }\n}\n```\n\n有关用法的详细信息，请查看 [`html!` 宏指南](concepts/html/introduction.mdx)]\n\n### Mounted\n\n`mounted()` 组件生命周期方法调用是在 `view()` 被处理并且 Yew 已经把组件挂载到 DOM 上之后，浏览器刷新页面之前。组件通常希望实现此方法以执行只能在组件渲染元素之后才能执行的操作。如果你想在做出一些更改后重新渲染组件，返回 `true` 就可以了。\n\n```rust\nuse stdweb::web::html_element::InputElement;\nuse stdweb::web::IHtmlElement;\nuse yew::prelude::*;\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    fn mounted(&mut self) -> ShouldRender {\n        if let Some(input) = self.node_ref.cast::<InputElement>() {\n            input.focus();\n        }\n        false\n    }\n}\n```\n\n:::note\n请注意，此生命周期方法不要求必须实现，默认情况下不会执行任何操作。\n:::\n\n### Update\n\n组件是动态的，可以注册以接收异步信息。`update()` 生命周期方法对于每个消息都会被调用。这使得组件可以根据消息的内容来更新自身，并决定是否需要重新渲染自己。消息可以由 HTML 元素监听器触发，或者由子组件，Agents，Services 或 Futures 发送。\n\n`update()` 可能看起来像下面这个例子：\n\n```rust\npub enum Msg {\n    SetInputEnabled(bool)\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n\n    // ...\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n       match msg {\n           Msg::SetInputEnabled(enabled) => {\n               if self.input_enabled != enabled {\n                   self.input_enabled = enabled;\n                   true // 重新渲染\n               } else {\n                   false\n               }\n           }\n       }\n    }\n}\n```\n\n### Change\n\n组件可能被其父节点重新渲染。发生这种情况时，它们可以接收新的属性（properties）并选择重新渲染。这种设计通过更改属性（properties）来促进父子组件之间的通信。你不是必须实现 `change()`，但是如果想在组件被创建后通过 props 来更新组件，则可能要这么做。\n\n一个原始的实现可能看起来像：\n\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn change(&mut self, props: Self::Properties) -> ShouldRender {\n       self.props = props;\n       true // 当提供了新的 props 将始终重新渲染。\n    }\n}\n```\n\n### Destroy\n\n组件从 DOM 上被卸载后，Yew 调用 `destroy()` 生命周期方法来支持任何必要的清理操作。这个方法是可选的，默认情况下不执行任何操作。\n\n## 关联类型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 表示组件可以处理以触发某些副作用的各种消息。例如，你可能有一条 `Click` 消息，该消息触发 API 请求或者切换 UI 组件的外观。通常的做法是在组件模块中创建一个叫做 `Msg` 的枚举并将其用作组件中的消息类型。通常将“message”缩写为“msg”。\n\n```rust\nenum Msg {\n    Click,\n}\n```\n\n`Properties` 表示从父级传递到组件的信息。此类型必须实现 `Properties` trait（通常通过派生），并且可以指定某些属性（properties）是必需的还是可选的。创建和更新组件时使用此类型。通常的做法是在组件模块中创建一个叫做 `Props` 的结构体并将其用作组件的 `Properties` 类型。通常将“properties”缩写为“props”。由于 props 是从父组件传递下来的，因此应用程序的根组件通常有一个类型为 `()` 的 `Properties`。如果你希望为根组件指定属性（properties），请使用 `App::mount_with_props` 方法。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/properties.mdx",
    "content": "---\ndescription: 父组件到子组件的通信\n---\n\n# 属性（Properties）\n\n如“组件（Components）”页面所述，Properties 用于父级到子组件的通信。\n\n## 派生宏\n\n不要尝试自己去实现 `Properties`，而是通过使用 `#[derive(Properties)]` 来派生它。\n\n### 必需属性\n\n默认情况下，实现了 `Properties` 的结构体中的字段是必需的。当缺少了该字段并且在 `html!` 宏中创建了组件时，将返回编译错误。对于具有可选属性的字段，使用 `#[prop_or_default]` 来使用该类型的默认值。要指定一个值，请使用 `#[prop_or_else(value)]`，其中 value 是该属性的默认值。例如，要将一个布尔值的默认值设置为 `true`，请使用属性 `#[prop_or_else(true)]`。可选属性通常使用 `Option`，其默认值为 `None`。\n\n### PartialEq\n\n如果可以的话，在你的 props 上派生 `PartialEq` 通常是很有意义的。这使用了一个**性能优化与最佳实践**部分解释了的技巧，可以更轻松地避免重新渲染。\n\n## Properties 的内存/速度开销\n\n记住组件的 `view` 函数签名：\n\n```rust\nfn view(&self) -> Html\n```\n\n你对组件的状态取了一个引用，并用来创建 `Html`。但是 properties 是有所有权的值（owned values）。这意味着为了创造它们并且将它们传递给子组件，我们需要获取 `view` 函数里提供的引用的所有权。这是在将引用传递给组件时隐式克隆引用完成的，以获得构成其 props 的有所有权的值。\n\n这意味着每个组件都有从其父级传递来的状态的独特副本，而且，每当你重新渲染一个组件时，该重新渲染组件的所有子组件的 props 都将被克隆。\n\n这意味着如果你将 _大量_ 数据作为 props（大小为 10 KB 的字符串）向下传递，则可能需要考虑将子组件转换为在父级运行返回 `Html` 的函数，因为这样就不会被强制克隆你的数据。\n\n另外，如果你不需要修改作为 props 传递的大数据，而只需要显示它，则可以将其包装在 `Rc` 中，以便仅克隆一个引用计数的指针，而不是数据本身。\n\n## 示例\n\n```rust\npub struct LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nimpl Default for LinkColor {\n    fn default() -> Self {\n        // 除非另有说明，否则链接的颜色将为蓝色\n        LinkColor::Blue\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标地址\n    href: String,\n    /// 如果链接文本很大，这将使得复制字符串开销更小\n    /// 除非有性能问题，否则通常不建议这么做\n    text: Rc<String>,\n    /// 链接的颜色\n    #[prop_or_default]\n    color: LinkColor,\n    /// 如果为 None，则 view 函数将不指定大小\n    #[prop_or_default]\n    size: Option<u32>\n    /// 当 view 函数没有指定 active，其默认为 true\n    #[prop_or_else(true)]\n    active: bool,\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: Refs\ndescription: 超出界限的 DOM 访问\n---\n\n`ref` 关键词可被用在任何 HTML 元素或组件内部以获得该项所附加到的 DOM 元素。这可被用于在 `view` 生命周期方法之外来对 DOM 进行更改。\n\n这对于获取 canvas 元素或者滚动到页面的不同部分是有用的。\n\n语法如下：\n\n```rust\n// 在 create 中\nself.node_ref = NodeRef::default();\n\n// 在 view 中\nhtml! {\n    <div ref={self.node_ref.clone()}></div>\n}\n\n// 在 update 中\nlet has_attributes = self.node_ref.cast::<Element>().unwrap().has_attributes();\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/agents.mdx",
    "content": "---\ntitle: Agents\ndescription: Yew 的 Actor 系统\n---\n\nAgents 和 Angular 的 [Services](https://angular.io/guide/architecture-services) 相似（但没有依赖注入），给 Yew 提供了 [Actor 模型](https://en.wikipedia.org/wiki/Actor_model)。Agents 可以用于在组件之间路由消息，而与它们在组件层次结构中的位置无关，或者可以用于协调全局状态，或者可以用于从主 UI 线程上卸载计算密集型任务，或者在不同的标签页间通信（在未来）。\n\nAgents 使用 [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) 同时运行来实现并发。\n\n## 生命周期\n\n![Agent lifecycle](https://user-images.githubusercontent.com/42674621/79125224-b6481d80-7d95-11ea-8e6a-ab9b52d1d8ac.png)\n\n## Agents 的类型\n\n#### Reaches\n\n- Job - 在 UI 线程上为每个新的 Bridge 生成一个新的 Agent。这对于将与浏览器通信的共享但独立的行为移出组件是很有用的。（待验证）任务完成后，Agent 将消失。\n- Context - Bridges 将生成或连接到 UI 线程上的 agent。这可用于在组件和其它 Agents 之间协调状态。当没有 Bridge 连接到该 Agent 时，Agent 将消失。\n- Private - 与 Job 相同，但运行在自己的 web worker 中。\n- Public - 与 Context 相同，但运行在自己的 web worker 中。\n- Global \\(WIP\\)\n\n## Agent 通信\n\n### Bridges\n\nBridges 将连接到一个 Agent 并且允许双向通信。\n\n### Dispatchers\n\nDispatchers 和 Bridges 类似，但是他们只能发送消息给 Agents。\n\n## 开销\n\nAgents 通过使用二进制码 bincode 序列化其消息来进行通信。因此，存在比仅调用函数相比更高的性能消耗。除非计算成本或者在任意组件间协调的需求超过消息传递的成本，否则你应该尽可能地在函数中包含你的应用逻辑。\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) example shows how components can use agents to communicate with each other.\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 自定义钩子（Custom Hooks）\ndescription: 定义你自己的 Hooks\n---\n\n## 定义自定义钩子\n\n组件中与状态有关的逻辑可以通过创建自定义 Hooks 提取到函数中。\n\n假设我们有一个组件，它订阅了一个代理（agent）并且会显示发送给它的消息。\n\n```rust\n#[function_component(ShowMessages)]\npub fn show_messages() -> Html {\n    let (state, set_state) = use_state(|| vec![]);\n\n    {\n        let mut state = Rc::clone(&state);\n        use_effect(move || {\n            let producer = EventBus::bridge(Callback::from(move |msg| {\n                let mut messages = (*state).clone();\n                messages.push(msg);\n                set_state(messages)\n            }));\n\n            || drop(producer)\n        });\n    }\n\n    let output = state.iter().map(|it| html! { <p>{ it }</p> });\n    html! { <div>{ for output }</div> }\n}\n```\n\n这段代码有一个问题：逻辑不能被另一个组件重用。如果我们构建另一个跟踪消息的组件，我们可以将逻辑移动到自定义钩子中，而不是复制代码。\n\n我们将首先创建一个名为`use_subscribe`的新函数。 `use_`前缀通常表示此函数是一个钩子。这个函数将不接受任何参数并返回`Rc<RefCell<Vec<String>>>` 。\n\n```rust\nfn use_subscribe() -> Rc<RefCell<Vec<String>>> {\n    // ...\n}\n```\n\n钩子的逻辑在`use_hook`的回调中。 `use_hook`指的是自定义 Hook 的处理函数。它接受 2 个参数： `hook_runner`和`initial_state_producer` 。\n\n`hook_runner`中包含了所有钩子的逻辑，它的回调的返回值又会被`use_hook`返回。 `hook_runner`需要 2 个参数：分别是对钩子和`hook_callback`它们两个的内部状态的可变引用。 而`hook_callback`同样也要 2 个参数：一个回调和一个 bool，回调接受`internal_state` ，也就是对内部状态实例的可变引用，并且会调执行实际的更改，还会返回表示`ShouldRender`的布尔值，第二个参数 bool 的用处是指示它是否在组件渲染后运行。`use_hook`的第二个参数`initial_state_producer`接受用于创建内部状态实例的回调。这里说的内部状态指的是一个实现了`Hook` trait 的结构体。\n\n现在让我们为`use_subscribe`钩子创建状态（state struct）。\n\n```rust\n/// `use_subscribe` internal state\nstruct UseSubscribeState {\n    /// holds all the messages received\n    pub messages: Rc<RefCell<Vec<String>>>,\n}\n\nimpl Hook for UseSubscribeState {}\n```\n\n接下来我们为`use_subscribe`添加实际逻辑。\n\n```rust\nfn use_subscribe() -> Rc<RefCell<Vec<String>>> {\n    use_hook(\n        // hook's handler. all the logic goes in here\n        |state: &mut UseSubscribeState, hook_callback| {\n            // calling other Hooks inside a hook\n            use_effect(move || {\n                let producer = EventBus::bridge(Callback::from(move |msg| {\n                    hook_callback(\n                        // where the mutations of state are performed\n                        |state| {\n                            (*state.messages).borrow_mut().deref_mut().push(msg);\n                            true // should re-render\n                        }, false // run post-render\n                    )\n                }));\n\n                || drop(producer)\n            });\n\n            // return from hook\n            state.messages.clone()\n        },\n        // initial state producer\n        || UseSubscribeState { messages: Rc::new(RefCell::new(vec![])) },\n    )\n}\n```\n\n现在我们可以使用自定义钩子了：\n\n```rust\n#[function_component(ShowMessages)]\npub fn show_messages() -> Html {\n    let state = use_subscribe();\n    let output = state.borrow().deref().into_iter().map(|it| html! { <p>{ it }</p> });\n\n    html! { <div>{ for output }</div> }\n}\n```\n\n需要特别注意的是创建自定义钩子时`use_hook`不是必须的，它们只是用来包含其他钩子。通常应避免使用`use_hook`。\n\n```rust\nfn use_subscribe() -> Rc<Vec<String>> {\n    let (state, set_state) = use_state(Vec::new);\n\n    use_effect(move || {\n        let producer = EventBus::bridge(Callback::from(move |msg| {\n            let mut messages = (*state).clone();\n            messages.push(msg);\n            set_state(messages)\n        }));\n        || drop(producer)\n    });\n\n    state\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 函数式组件\nsidebar_label: 简介\ndescription: 介绍函数式组件\nslug: /concepts/function-components\n---\n\n函数式组件是普通组件的简化版本。它们由一个接收 props 的函数组成，并通过返回`Html`来确定应该呈现什么。基本上，它是一个简化为`view`方法的组件。就其本身而言，这将是相当有限的，因为您只能创建纯组件，而这就是 Hook 大展身手的地方。Hook 允许函数组件无需实现`Component` trait，就可以使用状态（state）和其他 Yew 功能。\n\n## 创建函数式组件\n\n创建函数式组件的最简单方法是在函数前添加`#[function_component]`属性。\n\n```rust\n#[function_component(HelloWorld)]\nfn hello_world() -> Html {\n    html! { \"Hello world\" }\n}\n```\n\n### 更多细节\n\n函数式组件由两部分组成。首先， `FunctionProvider` trait 与`Component` trait 差不多，但它只有一个名为`run`方法。之后是`FunctionComponent`结构体，它封装了`FunctionProvider`类型并将其转换为实际的`Component` 。 `#[function_component]`属性本质上只是`FunctionProvider`并将其暴露在`FunctionComponent` 。\n\n### 钩子（Hooks）\n\n钩子（Hooks）就是让您“钩住”组件的状态（state）和/或生命周期并执行操作的函数。 除了 Yew 自带的一些预定义的 Hook。您也可以创建自己的。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/html/components.mdx",
    "content": "---\ndescription: 使用具有层次结构的组件来创建复杂的布局\n---\n\n# 组件\n\n## 基础\n\n任何实现了 `Component` trait 的类型都可被用在 `html!` 宏中：\n\n```rust\nhtml!{\n    <>\n        // 没有属性\n        <MyComponent />\n\n        // 具有属性\n        <MyComponent prop1=\"lorem\" prop2=\"ipsum\" />\n\n        // 同时提供全套的 props\n        <MyComponent ..props />\n    </>\n}\n```\n\n## 嵌套\n\n如果组件的 `Properties` 中有 `children` 字段，则可以被传递子组件。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <Container>\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n}\n```\n\n```rust title=\"container.rs\"\npub struct Container(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: Children,\n}\n\nimpl Component for Container {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n       html! {\n           <div id=\"container\">\n               { self.0.children.clone() }\n           </div>\n       }\n    }\n}\n```\n\n## 拥有 Props 的嵌套子组件\n\n如果包含组件标注了 children 的类型，则可以访问和更改嵌套组件的属性。在下面的示例中，`List` 组件可以包含 `ListItem` 组件。有关此模式的真实示例，请查看 `yew-router` 的源码。有关更高级的示例，请在 yew 主仓库中查看 `nested-list` 示例代码。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n}\n```\n\n```rust title=\"list.rs\"\npub struct List(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\nimpl Component for List {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n        html!{{\n            for self.0.children.iter().map(|mut item| {\n                item.props.value = format!(\"item-{}\", item.props.value);\n                item\n            })\n        }}\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/html/elements.mdx",
    "content": "---\ndescription: HTML 和 SVG 元素均受支持\n---\n\n# 元素\n\n## 标签结构\n\n元素标签必须是自闭合的 `<... />`，或是每个标签都有一个对应的闭合标签。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--标签 - 闭合标签-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"></div>\n}\n```\n\n<!--无效-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"> // <- 缺少闭合标签\n}\n```\n\n<!--自闭合-->\n\n```rust\nhtml! {\n  <input id=\"my_input\" />\n}\n```\n\n<!--无效-->\n\n```rust\nhtml! {\n  <input id=\"my_input\"> // <- 没有自闭合\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n:::note\n为方便起见，一些 _通常_ 需要闭合标签的元素是被**允许**自闭合的。例如，`html! { <div class=\"placeholder\" /> }` 这样写是有效的。\n:::\n\n## Children\n\n轻松创建复杂的嵌套 HTML 和 SVG 布局：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--HTML-->\n\n```rust\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n}\n```\n\n<!--SVG-->\n\n```rust\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <feGaussianBlur stdDeviation=\"2\"/>\n                <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## Classes\n\n有许多方便的选项可用于元素指定 classes：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--常量-->\n\n```rust\nhtml! {\n  <div class=\"container\"></div>\n}\n```\n\n<!--多个属性-->\n\n```rust\nhtml! {\n  <div class=\"container center-align\"></div>\n}\n```\n\n<!--插值-->\n\n```rust\nhtml! {\n  <div class={format!(\"{}-container\", size)}></div>\n}\n```\n\n<!--表达式-->\n\n```rust\nhtml! {\n  <div class={self.classes()}></div>\n}\n```\n\n<!--元组-->\n\n```rust\nhtml! {\n  <div class={(\"class-1\", \"class-2\")}></div>\n}\n```\n\n<!--Vector-->\n\n```rust\nhtml! {\n  <div class={vec![\"class-1\", \"class-2\"]}></div>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## 监听器\n\n监听器属性需要传递一个由闭包包裹的 `Callback`。创建回调的方式取决于你希望你的应用程序如何响应监听器事件：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Component 处理器-->\n\n```rust\nstruct MyComponent {\n    link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => {\n                // 处理 Click\n            }\n        }\n    }\n\n    fn view(&self) -> Html {\n        // 从组件 link 中创建回调来在组件中处理它\n        let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Agent 处理器-->\n\n```rust\nstruct MyComponent {\n    worker: Dispatcher<MyWorker>,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent {\n            worker: MyWorker::dispatcher()\n        }\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 从 worker 中创建回调来在另一个上下文中处理它\n        let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--其他情况-->\n\n```rust\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 创建一个短暂的回调\n        let click_callback = Callback::from(|| {\n            ConsoleService::log(\"clicked!\");\n        });\n\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/html/introduction.mdx",
    "content": "---\ndescription: 用于生成 HTML 和 SVG 的宏程序\nslug: /concepts/html\n---\n\n# 使用 html! 宏\n\n`html!` 宏允许你为组件编写声明式的 HTML 和 SVG。如果你使用过 React 的 JSX，将会感觉到非常熟悉。\n\n**重要提示**\n\n1. `html!` 宏调用中只能有一个根节点\n2. 空的 `html! {}` 宏调用是有效的但不会渲染任何内容\n3. 常量必须始终被引号括起来并被包含在大括号里：`html! { \"Hello, World\" }`\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/html/lists.mdx",
    "content": "# 列表\n\n## Fragments\n\n`html!` 宏总是要求一个单一的根节点。为了绕开这个限制，把内容包裹在一个空标签内是有效的：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--有效-->\n\n```rust\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n}\n```\n\n<!--无效-->\n\n```rust\n/* 错误：只允许一个 html 根元素 */\n\nhtml! {\n    <div></div>\n    <p></p>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## 迭代器\n\nYew 支持两种从迭代器构建 html 的语法：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--语法类型 1-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { self.props.items.iter().map(renderItem).collect::<Html>() }\n    </ul>\n}\n```\n\n<!--语法类型 2-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { for self.props.items.iter().map(renderItem) }\n    </ul>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/html/literals-and-expressions.mdx",
    "content": "# 常量和表达式\n\n## 常量\n\n如果一个表达式的类型本身实现了 `Display` （一个标准库中的 Trait），他们将会被转化成字符串并且作为一个 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 节点插入 DOM 中。\n\n所有的需要显示的文本必须被 `{}` 块包含，因为这些文本会被当做一个 Rust 表达式来处理。这一点上，Yew 中使用 HTML 的方式和正常 HTML 语法有巨大的区别。\n\n```rust\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n}\n```\n\n## 表达式\n\n你可以在 HTML 中使用 `{}` 块来插入 Rust 表达式，只要这些表达式最终可以被解析成 `Html`\n\n```rust\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n}\n```\n\n通常我们会把这些表达式写进函数或者闭包中来增加可读性：\n\n```rust\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/concepts/router.mdx",
    "content": "---\ndescription: Yew 的官方 Router\n---\n\n# Router\n\n[https://crates.io/crates/yew-router](https://crates.io/crates/yew-router)\n\nRouters 在单页应用（SPA）中根据 URL 的不同显示不同的页面。当点击一个链接时，Router 在本地设置 URL 以指向应用程序中有效的路由，而不是默认请求一个不同的远程资源。然后 Router 检测到此更改后决定要渲染的内容。\n\n## 核心元素\n\n### Route\n\n包含一个字符串，该字符串表示网址中域名之后的所有内容，还可以选择表示存储在 history api 中的状态。\n\n### RouteService\n\n与浏览器通信以获取和设置路由。\n\n### RouteAgent\n\n拥有一个 RouteService，并用于当路由改变时协调更新，无论更新是来自应用程序自身逻辑还是来自浏览器触发的事件。\n\n### Switch\n\n`Switch` trait 用于在该 trait 的实现者之间转换 `Route`。\n\n### Router\n\nRouter 组件同 `RouterAgent` 进行通信，并将自动把它从 Agent 那里获得的 Routes 解析为 Switches，并通过 `render` 属性暴露该 Switch，该属性允许指定将生成的 Switch 转换为 `HTML` 的方式。\n\n## 如何使用 Router\n\n首先，你要创建一个表征你的应用程序所有状态的类型。请注意，虽然这通常是一个枚举，但也支持结构体，并且你可以在内部嵌套实现了 `Switch` trait 的其他项。\n\n然后你应该为了你创建的类型派生 `Switch`。对于枚举，每一个成员都必须用 `#[to = \"/some/route\"]` 进行标注，如果你使用结构体，则标注必须出现在结构体声明之外。\n\n请注意，由派生宏为 `Switch` 生成的实现，将尝试从头到尾依次创建每个成员，因此，如果任何路由可能与你指定的两个 `to` 标注相匹配，那么第一个会被匹配，第二个将永远不会被尝试。\n\n你还可以在 `#[to = \"\"]` 标注中使用 `{}` 的变体来捕获片段。`{}` 表示捕获文本直到下一个分隔符（根据上下文可能是\"/\"，\"?\"，\"&\" 或 \"\\#\"）。`{*}` 表示捕获文本直到后续字符匹配为止，如果不存在任何字符，则它将匹配任何内容。`{<number>}` 表示捕获文本直到遇到指定数目的分隔符为止（例如：`{2}` 将一直捕获文本直到遇到两个分隔符为止）。\n\n对于具有命名字段的结构体和枚举，你必须在捕获组中指定字段的名称，例如：`{user_name}` 或 `{*:age}`。\n\nSwitch trait 适用于比字符串更结构化的捕获组。你可以指定实现了 `Switch` trait 的任何类型。因此，你可以指定捕获组为 `usize`，并且如果 URL 的捕获部分无法转换为它，则该成员不会被匹配。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/getting-started/build-a-sample-app.mdx",
    "content": "# 第一个简单的 App\n\n首先创建一个二进制项目:\n\n```bash\ncargo new --bin yew-app && cd yew-app\n```\n\n添加 `yew` 到你的依赖库中（[这里](https://docs.rs/yew) 可以查看最新版本的 Yew）\n\n```text title=\"Cargo.toml\"\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nauthors = [\"Yew App Developer <name@example.com>\"]\nedition = \"2018\"\n\n[dependencies]\nyew = { version = \"0.14.3\", features = [\"std_web\"] }\n```\n\n将这份代码复制到你的 `src/main.rs` 文件中:\n\n```rust title=\"src/main.rs\"\nuse yew::prelude::*;\n\nstruct Model {\n    link: ComponentLink<Self>,\n    value: i64,\n}\n\nenum Msg {\n    AddOne,\n}\n\nimpl Component for Model {\n    type Message = Msg;\n    type Properties = ();\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        Self {\n            link,\n            value: 0,\n        }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::AddOne => self.value += 1\n        }\n        true // 指示组件应该重新渲染\n    }\n\n    fn view(&self) -> Html {\n        html! {\n            <div>\n                <button onclick={self.link.callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n                <p>{ self.value }</p>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    yew::initialize();\n    App::<Model>::new().mount_to_body();\n}\n```\n\n这份代码将构建你的称为 `Model` 的 `Component` 根组件，它会显示一个按钮，当你点击它时，`Model` 将会更新自己的状态。特别注意 `main()` 中的 `App::<Model>::new().mount_to_body()`，它会启动你的应用并将其挂载到页面的 `<body>` 标签中。如果你想使用任何动态属性来启动应用程序，则可以使用 `App::<Model>::new().mount_to_body_with_props(..)`。\n\n## 运行你的应用程序!\n\n启动并运行你的应用的最快方式就是使用 [`cargo-web`](https://github.com/koute/cargo-web)。如果你还没有的话，请用 `cargo install cargo-web` 命令来安装这个工具然后通过运行下述命令来构建和启动一个开发服务器：\n\n```bash\ncargo web start\n```\n\n`cargo-web` 将会自动为你添加 `wasm32-unknown-unknown` 作为目标代码，然后构建你的应用，你的应用将默认在 [http://\\[::1\\]:8000](http://[::1]:8000) 被访问。可以通过 `cargo web start --help` 命令来获取更多选项和帮助。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/getting-started/examples.mdx",
    "content": "# 通过例子学习\n\nYew 的 github 项目中就包含了各种各样的示例（这些项目在不同程度的维护中）。我们建议仔细地学习它们, 了解如何使用不同的框架特性. 我们在书中有纰漏和错误的时候也欢迎 pull-requests 和提交 issues ♥️\n\n- [**Todo App（代办事项）\\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/todomvc)\n- [**Todo App（代办事项）\\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/todomvc)\n- [**Custom Components（自定义 Component 组件）**](https://github.com/yewstack/yew/tree/v0.14.0/examples/custom_components)\n- [**Multi-threading \\(Agents\\)（多线程 Agents）\\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/multi_thread)\n- [**Multi-threading \\(Agents\\)（多线程 Agents）\\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/multi_thread)\n- [**Timer Service（计时器）**](https://github.com/yewstack/yew/tree/v0.14.0/examples/timer)\n- [**Nested Components（嵌套 Component 组件）**](https://github.com/yewstack/yew/tree/v0.14.0/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/more/css.mdx",
    "content": "# CSS\n\n&lt;TODO&gt;\n\n对适当的 CSS 支持的提案可以在这里找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/more/debugging.mdx",
    "content": "# Debugging\n\n## Panics\n\nPlease use the [`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook) crate for nicer stacktraces with Rust symbols. Note, that it is not compatible with apps built with `cargo-web`.\n\n## Console Logging\n\nIn general, Wasm web apps are able to interact with Browser APIs, and the `console.log` api is no exception. There are a few options available:\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\nThis crate integrates with the familiar Rust `log` crate:\n\n```rust\n// setup\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n}\n\n// usage\nlog::info!(\"Update: {:?}\", msg);\n```\n\n### **\\`\\`**[**`ConsoleService`**](https://docs.rs/yew/0.13.2/yew/services/console/struct.ConsoleService.html)**\\`\\`**\n\nThis service is included within yew and is available when the `\"services\"` feature is enabled:\n\n```rust\n// usage\nConsoleService::info(format!(\"Update: {:?}\", msg).as_ref());\n```\n\n## Source Maps\n\nThere is currently no first-class support for source maps for Rust / Wasm web apps. This, of course, is subject to change. If this is no longer true or if progress is made, please suggest a change!\n\n### Latest Info\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) don’t support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/more/roadmap.mdx",
    "content": "---\ndescription: Yew 框架规划功能的路线图\n---\n\n# 路线图\n\n## `v1.0.0`\n\n### 规划中的功能\n\n- 标记 key 的列表项：[https://github.com/yewstack/yew/issues/479](https://github.com/yewstack/yew/issues/479)\n- 路由：[https://github.com/yewstack/yew_router](https://github.com/yewstack/yew_router)\n\n### 生产环境准备\n\n- 浏览器兼容性\n- 提高 Yew 框架的测试覆盖率\n- 增加性能基准测试：[https://github.com/yewstack/yew/issues/5](https://github.com/yewstack/yew/issues/5)\n\n### 指南\n\n- 最佳实践：[https://yew.rs/optimizations](https://yew.rs/optimizations)\n- 端到端教程\n- Futures / 并发\n- CSS / 样式\n- 测试\n- 状态管理\n\n## 未来\n\n### 潜在功能\n\n- 服务端渲染：[https://github.com/yewstack/yew/issues/41](https://github.com/yewstack/yew/issues/41)\n- 组件库：[https://github.com/yewstrap/yewstrap](https://github.com/yewstrap/yewstrap)\n- 代码分割：[https://github.com/yewstack/yew/issues/599](https://github.com/yewstack/yew/issues/599)\n- 允许不同的虚拟 DOM 后端：[https://github.com/yewstack/yew/issues/482](https://github.com/yewstack/yew/issues/482)\n- 反思 Services：[https://github.com/yewstack/yew/issues/364](https://github.com/yewstack/yew/issues/364)\n- 成熟的工具包：[https://github.com/yewstack/yewtil](https://github.com/yewstack/yewtil)\n- HTML 模板备选方案：[https://github.com/yewstack/yew/issues/438](https://github.com/yewstack/yew/issues/438)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20/more/testing.mdx",
    "content": "---\ndescription: 测试你的应用程序\n---\n\n# 测试\n\n&lt;TODO&gt;\n\n## Rust WebDriving\n\n使用 Rust 以编程方式驱动 UI 集成测试，[fantoccini](https://crates.io/crates/fantoccini) 是一个推荐的选择。它允许你通过使用 CSS 选择器来查找特定的元素，然后对它们执行特定的操作，例如输入文本，点击按钮，或等待特定时间以使客户端代码执行（例如等待一个网络请求完成并导致 UI 改变），来测试你的网站。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.20.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.20\",\n    \"description\": \"The label for version 0.20\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Using Basic Web Technologies In Yew\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew's Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may need in one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[function_component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[function_component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: '有关框架的底层细节'\n---\n\n# 底层库的内部细节\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '性能优化与最佳实践'\nsidebar_label: Optimizations\ndescription: 加速你的应用程序\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nTo avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications, it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component or just a big\nfunction that produces `Html`. Code that is shared between the crates containing different parts of\nthe application could be stored in a separate crate which the project depends on.\nIn the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and additionally render the component you are working on.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther, it is possible to optimize the size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading:\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[function_component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/server-side-rendering.md",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回调（Callbacks）'\ndescription: 'ComponentLink 和 Callbacks'\n---\n\n## Callbacks\n\nCallbacks 用于与 Yew 中的 services，agents 和父组件进行通信。它们仅仅是个 `Fn`，并由 `Rc` 包裹以允许被克隆。\n\n它们有一个 `emit` 函数，该函数将它的 `<IN>` 类型作为参数并将其转换为目标所期望的消息。如果一个回调从父组件中通过 props 提供给子组件，则子组件可以在其 `update` 生命周期钩子中对该回调调用 `emit`，以将消息发送回父组件。在 `html!` 宏内被提供作为 props 的闭包或函数会自动转换为 Callbacks。\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[function_component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命周期'\ndescription: '组件及其生命周期钩子'\n---\n\n`Component` trait 有许多需要实现的方法；Yew 会在组件生命周期的不同阶段调用这些方法。\n\n## 生命周期\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命周期方法\n\n### Create\n\n当一个组件被创建时，它会从其父组件接收属性（properties）并存储在传递给 `create` 方法的 `Context<Self>` 中。\n属性（properties）可用于初始化组件的状态，\"link\"可用于注册回调或向组件发送消息。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法允许你描述组件应该如何渲染到 DOM。使用 Rust 函数编写类似 HTML 的代码可能会变得相当混乱，\n因此 Yew 提供了一个叫做 `html!` 的宏用于声明 HTML 和 SVG 节点（以及附加属性和事件监听器），\n并提供了一种方便的方式来渲染子组件。这个宏在某种程度上类似于 React 的 JSX（撇开编程语言的差异不谈）。\n一个区别是 Yew 提供了类似 Svelte 的属性简写语法，你可以直接写 `{onclick}`，而不是写 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n有关用法的详细信息，请查看 [`html!` 宏指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 组件生命周期方法在 `view` 被调用并且 Yew 已将结果渲染到 DOM 之后，但在浏览器刷新页面之前被调用。\n当你想要执行只能在组件渲染元素之后才能完成的操作时，这个方法非常有用。\n还有一个名为 `first_render` 的参数，可用于确定此函数是在第一次渲染时被调用，还是在后续渲染时被调用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n注意，此生命周期方法不需要实现，默认情况下不会执行任何操作。\n:::\n\n### Update\n\n与组件的通信主要通过消息进行，这些消息由 `update` 生命周期方法处理。\n这允许组件根据消息的内容更新自身，并决定是否需要重新渲染。\n消息可以由事件监听器、子组件、Agents、Services 或 Futures 发送。\n\n以下是 `update` 实现的示例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\n组件可能会被其父组件重新渲染。当这种情况发生时，它们可能会收到新的属性并需要重新渲染。\n这种设计通过简单地改变属性值来促进父组件到子组件的通信。\n有一个默认实现会在属性发生变化时重新渲染组件。\n\n### Destroy\n\n组件从 DOM 卸载后，Yew 会调用 `destroy` 生命周期方法；\n如果你需要在组件销毁之前清理组件先前操作的内容，这是必要的。\n此方法是可选的，默认情况下不执行任何操作。\n\n### 无限循环\n\n使用 Yew 的生命周期方法可能会出现无限循环，但只有在尝试在每次渲染后更新同一组件，\n并且该更新也请求组件重新渲染时才会发生。\n\n一个简单的示例如下：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\n让我们来看看这里发生了什么：\n\n1. 使用 `create` 函数创建组件。\n2. 调用 `view` 方法，以便 Yew 知道要渲染什么到浏览器 DOM。\n3. 调用 `rendered` 方法，它使用 `Context` 链接安排了一个更新消息。\n4. Yew 完成后渲染阶段。\n5. Yew 检查预定的事件，发现更新消息队列不为空，因此处理这些消息。\n6. 调用 `update` 方法，它返回 `true` 表示有内容已更改，组件需要重新渲染。\n7. 跳回步骤 2。\n\n你仍然可以在 `rendered` 方法中安排更新，这通常很有用，\n但在这样做时要考虑你的组件将如何终止这个循环。\n\n## 关联类型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 类型用于在事件发生后向组件发送消息；\n例如，你可能希望在用户点击按钮或向下滚动页面时执行某些操作。\n由于组件通常需要响应多个事件，`Message` 类型通常是一个枚举，\n其中每个变体都是要处理的事件。\n\n在组织代码库时，明智的做法是将 `Message` 类型的定义包含在定义组件的同一模块中。\n你可能会发现采用一致的消息类型命名约定很有帮助。\n一种选择（尽管不是唯一的）是将类型命名为 `ComponentNameMsg`，\n例如，如果你的组件叫 `Homepage`，那么你可能会将类型命名为 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示从父组件传递给组件的信息。此类型必须实现 `Properties` trait（通常通过派生它）并可以指定某些属性是必需的还是可选的。此类型在创建和更新组件时使用。常见的做法是在组件模块中创建一个名为 `Props` 的结构体，并将其用作组件的 `Properties` 类型。通常将\"properties\"缩写为\"props\"。由于 props 是从父组件传递下来的，应用程序的根组件通常具有 `()` 类型的 `Properties`。如果你希望为根组件指定属性，请使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多关于属性的信息](./properties)\n:::\n\n## 生命周期上下文\n\n所有组件生命周期方法都接受一个上下文对象。此对象提供了对组件作用域的引用，\n允许向组件发送消息以及访问传递给组件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '属性（Properties）'\ndescription: '父组件到子组件的通信'\n---\n\nProperties 用于父级到子组件的通信。\n每个组件都有一个关联的属性类型，描述了从父级传递下来的内容。\n理论上，这可以是任何实现了 `Properties` trait 的类型，但实际上，\n没有理由不使用一个结构体，其中每个字段都代表一个属性。\n\n## 派生宏\n\n不要尝试自己去实现 `Properties`，而是通过使用 `#[derive(Properties)]` 来派生它。\n派生 `Properties` 的类型还必须实现 `PartialEq`。\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they are set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: Refs\ndescription: 超出界限的 DOM 访问\n---\n\n`ref` 关键词可被用在任何 HTML 元素或组件内部以获得该项所附加到的 DOM 元素。这可被用于在 `view` 生命周期方法之外来对 DOM 进行更改。\n\n这对于获取 canvas 元素或者滚动到页面的不同部分是有用的。\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\n语法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/agents.mdx",
    "content": "---\ntitle: Agents\ndescription: Yew 的 Actor 系统\n---\n\nAgents 和 Angular 的 [Services](https://angular.io/guide/architecture-services) 相似（但没有依赖注入），给 Yew 提供了 [Actor 模型](https://en.wikipedia.org/wiki/Actor_model)。Agents 可以用于在组件之间路由消息，而与它们在组件层次结构中的位置无关，或者可以用于协调全局状态，或者可以用于从主 UI 线程上卸载计算密集型任务，或者在不同的标签页间通信（在未来）。\n\nAgents 使用 [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) 同时运行来实现并发。\n\n## 生命周期\n\n![Agent lifecycle](https://user-images.githubusercontent.com/42674621/79125224-b6481d80-7d95-11ea-8e6a-ab9b52d1d8ac.png)\n\n## Agents 的类型\n\n#### Reaches\n\n- Job - 在 UI 线程上为每个新的 Bridge 生成一个新的 Agent。这对于将与浏览器通信的共享但独立的行为移出组件是很有用的。（待验证）任务完成后，Agent 将消失。\n- Context - Bridges 将生成或连接到 UI 线程上的 agent。这可用于在组件和其它 Agents 之间协调状态。当没有 Bridge 连接到该 Agent 时，Agent 将消失。\n- Private - 与 Job 相同，但运行在自己的 web worker 中。\n- Public - 与 Context 相同，但运行在自己的 web worker 中。\n- Global \\(WIP\\)\n\n## Agent 通信\n\n### Bridges\n\nBridges 将连接到一个 Agent 并且允许双向通信。\n\n### Dispatchers\n\nDispatchers 和 Bridges 类似，但是他们只能发送消息给 Agents。\n\n## 开销\n\nAgents 通过使用二进制码 bincode 序列化其消息来进行通信。因此，存在比仅调用函数相比更高的性能消耗。除非计算成本或者在任意组件间协调的需求超过消息传递的成本，否则你应该尽可能地在函数中包含你的应用逻辑。\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) example shows how components can use agents to communicate with each other.\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, function_component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[function_component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[function_component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[function_component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[function_component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[function_component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[function_component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 自定义钩子（Custom Hooks）\ndescription: 定义你自己的 Hooks\n---\n\n## 定义自定义钩子\n\n组件中与状态有关的逻辑可以通过创建自定义 Hooks 提取到函数中。\n\n假设我们有一个组件，它订阅了一个代理（agent）并且会显示发送给它的消息。\n\n```rust\n#[function_component(ShowMessages)]\npub fn show_messages() -> Html {\n    let (state, set_state) = use_state(|| vec![]);\n\n    {\n        let mut state = Rc::clone(&state);\n        use_effect(move || {\n            let producer = EventBus::bridge(Callback::from(move |msg| {\n                let mut messages = (*state).clone();\n                messages.push(msg);\n                set_state(messages)\n            }));\n\n            || drop(producer)\n        });\n    }\n\n    let output = state.iter().map(|it| html! { <p>{ it }</p> });\n    html! { <div>{ for output }</div> }\n}\n```\n\n这段代码有一个问题：逻辑不能被另一个组件重用。如果我们构建另一个跟踪消息的组件，我们可以将逻辑移动到自定义钩子中，而不是复制代码。\n\n我们将首先创建一个名为`use_subscribe`的新函数。 `use_`前缀通常表示此函数是一个钩子。这个函数将不接受任何参数并返回`Rc<RefCell<Vec<String>>>` 。\n\n```rust\nfn use_subscribe() -> Rc<RefCell<Vec<String>>> {\n    // ...\n}\n```\n\n钩子的逻辑在`use_hook`的回调中。 `use_hook`指的是自定义 Hook 的处理函数。它接受 2 个参数： `hook_runner`和`initial_state_producer` 。\n\n`hook_runner`中包含了所有钩子的逻辑，它的回调的返回值又会被`use_hook`返回。 `hook_runner`需要 2 个参数：分别是对钩子和`hook_callback`它们两个的内部状态的可变引用。 而`hook_callback`同样也要 2 个参数：一个回调和一个 bool，回调接受`internal_state` ，也就是对内部状态实例的可变引用，并且会调执行实际的更改，还会返回表示`ShouldRender`的布尔值，第二个参数 bool 的用处是指示它是否在组件渲染后运行。`use_hook`的第二个参数`initial_state_producer`接受用于创建内部状态实例的回调。这里说的内部状态指的是一个实现了`Hook` trait 的结构体。\n\n现在让我们为`use_subscribe`钩子创建状态（state struct）。\n\n```rust\n/// `use_subscribe` internal state\nstruct UseSubscribeState {\n    /// holds all the messages received\n    pub messages: Rc<RefCell<Vec<String>>>,\n}\n\nimpl Hook for UseSubscribeState {}\n```\n\n接下来我们为`use_subscribe`添加实际逻辑。\n\n```rust\nfn use_subscribe() -> Rc<RefCell<Vec<String>>> {\n    use_hook(\n        // hook's handler. all the logic goes in here\n        |state: &mut UseSubscribeState, hook_callback| {\n            // calling other Hooks inside a hook\n            use_effect(move || {\n                let producer = EventBus::bridge(Callback::from(move |msg| {\n                    hook_callback(\n                        // where the mutations of state are performed\n                        |state| {\n                            (*state.messages).borrow_mut().deref_mut().push(msg);\n                            true // should re-render\n                        }, false // run post-render\n                    )\n                }));\n\n                || drop(producer)\n            });\n\n            // return from hook\n            state.messages.clone()\n        },\n        // initial state producer\n        || UseSubscribeState { messages: Rc::new(RefCell::new(vec![])) },\n    )\n}\n```\n\n现在我们可以使用自定义钩子了：\n\n```rust\n#[function_component(ShowMessages)]\npub fn show_messages() -> Html {\n    let state = use_subscribe();\n    let output = state.borrow().deref().into_iter().map(|it| html! { <p>{ it }</p> });\n\n    html! { <div>{ for output }</div> }\n}\n```\n\n需要特别注意的是创建自定义钩子时`use_hook`不是必须的，它们只是用来包含其他钩子。通常应避免使用`use_hook`。\n\n```rust\nfn use_subscribe() -> Rc<Vec<String>> {\n    let (state, set_state) = use_state(Vec::new);\n\n    use_effect(move || {\n        let producer = EventBus::bridge(Callback::from(move |msg| {\n            let mut messages = (*state).clone();\n            messages.push(msg);\n            set_state(messages)\n        }));\n        || drop(producer)\n    });\n\n    state\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函数式组件'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[function_component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{function_component, html, Html};\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[function_component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '属性 (Properties)'\ndescription: '父子组件通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n属性 (Properties) 通常被简称为 \"Props\"。\n\n:::\n\n属性 (Properties) 本质上是 Yew 可以监视的组件参数。\n\n一个类型必须先实现 `Properties` 特征才能被用作组件的属性。\n\n## 响应性\n\nYew 在重新渲染时会在协调虚拟 DOM 时检查 props 是否已更改，以了解是否需要重新渲染嵌套组件。这样，Yew 可以被认为是一个非常响应式的框架，因为来自父组件的更改总是会向下传播，视图永远不会与来自 props/状态的数据不同步。\n\n:::tip\n\n如果您还没有完成 [教程](../../tutorial)，请尝试一下并自己测试这种响应性！\n\n:::\n\n## 派生宏\n\nYew 提供了一个派生宏来轻松地在结构体上实现 `Properties` 特征。\n\n派生 `Properties` 的类型还必须实现 `PartialEq`，以便 Yew 可以进行数据比较。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函数组件中使用\n\n属性 `#[function_component]` 允许可选地在函数参数中接收 Props。要提供它们，它们通过 `html!` 宏中的属性分配。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{props.is_loading.clone()}</> }\n}\n\n// 然后提供属性\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{function_component, html, Html};\n\n\n\n\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 没有要提供的属性\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld />}\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生宏字段属性\n\n派生 `Properties` 时，默认情况下所有字段都是必需的。\n以下属性允许您为属性提供默认值，当父组件没有设置它们时将使用这些默认值。\n\n:::tip\n属性在 Rustdoc 生成的文档中不可见。您的属性的文档字符串应该提及属性是否是可选的以及是否有特殊的默认值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` 特征用字段类型的默认值初始化属性值。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading.clone() {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 然后像这样使用默认值\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// 或者不覆盖默认值\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 来初始化属性值。`value` 可以是任何返回字段类型的表达式。\n例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。表达式在构造属性时被评估，并且没有给出明确值时应用。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or(\"Bob\".to_string())]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// 然后像这样使用默认值\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// 或者不覆盖默认值\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n调用 `function` 来初始化属性值。`function` 应该有签名 `FnMut() -> T`，其中 `T` 是字段类型。当没有为该属性给出明确值时，该函数被调用。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\nfn create_default_name() -> String {\n    \"Bob\".to_string()\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// 然后像这样使用默认值\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// 或者不覆盖默认值\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的内存/速度开销\n\n内部属性是引用计数的。这意味着只有一个共享指针会沿着组件树向下传递给 props。这节省了我们不得不克隆整个 props 的成本，这可能很昂贵。\n\n:::tip\n使用 `AttrValue`，这是我们用于属性值的自定义类型，而不是将它们定义为 String 或其他类似类型。\n:::\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n宏使用与结构体表达式相同的语法，除了您不能使用属性或基本表达式（`Foo { ..base }`）。类型路径可以直接指向 props（`path::to::Props`）或指向组件的关联属性（`MyComp::Properties`）。\n\n```rust\nuse yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or(AttrValue::from(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n#[function_component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = props! {\n        Props {} // 注意我们不需要指定 name 属性\n    };\n    // highlight-end\n    html! {<HelloWorld ..pre_made_props />}\n}\n```\n\n## 评估顺序\n\nProps 按指定的顺序进行评估，如以下示例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n虽然几乎任何 Rust 类型都可以作为属性传递，但有一些应该避免的反模式。这些包括但不限于：\n\n1. 使用 `String` 类型而不是 `AttrValue`。 <br />\n   **为什么不好？** `String` 克隆成本很高。当属性值与钩子和回调一起使用时，通常需要克隆。`AttrValue` 是一个引用计数的字符串 (`Rc<str>`) 或一个 `&'static str`，因此非常便宜克隆。<br />\n   **注意**：`AttrValue` 内部是来自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看该包以了解更多信息。\n2. 使用内部可变性。 <br />\n   **为什么不好？** 内部可变性（例如 `RefCell`、`Mutex` 等）应该 _通常_ 避免使用。它可能会导致重新渲染问题（Yew 不知道状态何时发生了变化），因此您可能需要手动强制重新渲染。就像所有事物一样，它有其用武之地。请谨慎使用。\n3. 使用 `Vec<T>` 类型而不是 `IArray<T>`。 <br />\n   **为什么不好？** `Vec<T>`，就像 `String` 一样，克隆成本也很高。`IArray<T>` 是一个引用计数的切片 (`Rc<[T]>`) 或一个 `&'static [T]`，因此非常便宜克隆。<br />\n   **注意**：`IArray<T>` 可以从 [implicit-clone](https://crates.io/crates/implicit-clone) 导入。查看该包以了解更多信息。\n4. 您发觉可能的新内容。您是否遇到了一个希望早点了解清楚的边缘情况？请随时创建一个问题或向本文档提供修复的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一个实验性包，允许您根据函数的参数动态创建 Props 结构体。如果属性结构体永远不会被重用，这可能会很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/html/components.mdx",
    "content": "---\ndescription: 使用具有层次结构的组件来创建复杂的布局\n---\n\n# 组件\n\n## 基础\n\n任何实现了 `Component` trait 的类型都可被用在 `html!` 宏中：\n\n```rust\nhtml!{\n    <>\n        // 没有属性\n        <MyComponent />\n\n        // 具有属性\n        <MyComponent prop1=\"lorem\" prop2=\"ipsum\" />\n\n        // 同时提供全套的 props\n        <MyComponent ..props />\n    </>\n}\n```\n\n## 嵌套\n\n如果组件的 `Properties` 中有 `children` 字段，则可以被传递子组件。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <Container>\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n}\n```\n\n```rust title=\"container.rs\"\npub struct Container(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: Children,\n}\n\nimpl Component for Container {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n       html! {\n           <div id=\"container\">\n               { self.0.children.clone() }\n           </div>\n       }\n    }\n}\n```\n\n## 拥有 Props 的嵌套子组件\n\n如果包含组件标注了 children 的类型，则可以访问和更改嵌套组件的属性。在下面的示例中，`List` 组件可以包含 `ListItem` 组件。有关此模式的真实示例，请查看 `yew-router` 的源码。有关更高级的示例，请在 yew 主仓库中查看 `nested-list` 示例代码。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n}\n```\n\n```rust title=\"list.rs\"\npub struct List(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\nimpl Component for List {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n        html!{{\n            for self.0.children.iter().map(|mut item| {\n                item.props.value = format!(\"item-{}\", item.props.value);\n                item\n            })\n        }}\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/html/elements.mdx",
    "content": "---\ndescription: HTML 和 SVG 元素均受支持\n---\n\n# 元素\n\n## 标签结构\n\n元素标签必须是自闭合的 `<... />`，或是每个标签都有一个对应的闭合标签。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--标签 - 闭合标签-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"></div>\n}\n```\n\n<!--无效-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"> // <- 缺少闭合标签\n}\n```\n\n<!--自闭合-->\n\n```rust\nhtml! {\n  <input id=\"my_input\" />\n}\n```\n\n<!--无效-->\n\n```rust\nhtml! {\n  <input id=\"my_input\"> // <- 没有自闭合\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n:::note\n为方便起见，一些 _通常_ 需要闭合标签的元素是被**允许**自闭合的。例如，`html! { <div class=\"placeholder\" /> }` 这样写是有效的。\n:::\n\n## Children\n\n轻松创建复杂的嵌套 HTML 和 SVG 布局：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--HTML-->\n\n```rust\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n}\n```\n\n<!--SVG-->\n\n```rust\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <feGaussianBlur stdDeviation=\"2\"/>\n                <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## Classes\n\n有许多方便的选项可用于元素指定 classes：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--常量-->\n\n```rust\nhtml! {\n  <div class=\"container\"></div>\n}\n```\n\n<!--多个属性-->\n\n```rust\nhtml! {\n  <div class=\"container center-align\"></div>\n}\n```\n\n<!--插值-->\n\n```rust\nhtml! {\n  <div class={format!(\"{}-container\", size)}></div>\n}\n```\n\n<!--表达式-->\n\n```rust\nhtml! {\n  <div class={self.classes()}></div>\n}\n```\n\n<!--元组-->\n\n```rust\nhtml! {\n  <div class={(\"class-1\", \"class-2\")}></div>\n}\n```\n\n<!--Vector-->\n\n```rust\nhtml! {\n  <div class={vec![\"class-1\", \"class-2\"]}></div>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## 监听器\n\n监听器属性需要传递一个由闭包包裹的 `Callback`。创建回调的方式取决于你希望你的应用程序如何响应监听器事件：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Component 处理器-->\n\n```rust\nstruct MyComponent {\n    link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => {\n                // 处理 Click\n            }\n        }\n    }\n\n    fn view(&self) -> Html {\n        // 从组件 link 中创建回调来在组件中处理它\n        let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Agent 处理器-->\n\n```rust\nstruct MyComponent {\n    worker: Dispatcher<MyWorker>,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent {\n            worker: MyWorker::dispatcher()\n        }\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 从 worker 中创建回调来在另一个上下文中处理它\n        let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--其他情况-->\n\n```rust\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 创建一个短暂的回调\n        let click_callback = Callback::from(|| {\n            ConsoleService::log(\"clicked!\");\n        });\n\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/html/introduction.mdx",
    "content": "---\ndescription: 用于生成 HTML 和 SVG 的宏程序\nslug: /concepts/html\n---\n\n# 使用 html! 宏\n\n`html!` 宏允许你为组件编写声明式的 HTML 和 SVG。如果你使用过 React 的 JSX，将会感觉到非常熟悉。\n\n**重要提示**\n\n1. `html!` 宏调用中只能有一个根节点\n2. 空的 `html! {}` 宏调用是有效的但不会渲染任何内容\n3. 常量必须始终被引号括起来并被包含在大括号里：`html! { \"Hello, World\" }`\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/html/lists.mdx",
    "content": "# 列表\n\n## Fragments\n\n`html!` 宏总是要求一个单一的根节点。为了绕开这个限制，把内容包裹在一个空标签内是有效的：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--有效-->\n\n```rust\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n}\n```\n\n<!--无效-->\n\n```rust\n/* 错误：只允许一个 html 根元素 */\n\nhtml! {\n    <div></div>\n    <p></p>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## 迭代器\n\nYew 支持两种从迭代器构建 html 的语法：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--语法类型 1-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { self.props.items.iter().map(renderItem).collect::<Html>() }\n    </ul>\n}\n```\n\n<!--语法类型 2-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { for self.props.items.iter().map(renderItem) }\n    </ul>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/html/literals-and-expressions.mdx",
    "content": "# 常量和表达式\n\n## 常量\n\n如果一个表达式的类型本身实现了 `Display` （一个标准库中的 Trait），他们将会被转化成字符串并且作为一个 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 节点插入 DOM 中。\n\n所有的需要显示的文本必须被 `{}` 块包含，因为这些文本会被当做一个 Rust 表达式来处理。这一点上，Yew 中使用 HTML 的方式和正常 HTML 语法有巨大的区别。\n\n```rust\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n}\n```\n\n## 表达式\n\n你可以在 HTML 中使用 `{}` 块来插入 Rust 表达式，只要这些表达式最终可以被解析成 `Html`\n\n```rust\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n}\n```\n\n通常我们会把这些表达式写进函数或者闭包中来增加可读性：\n\n```rust\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/concepts/router.mdx",
    "content": "---\ndescription: Yew 的官方 Router\n---\n\n# Router\n\n[https://crates.io/crates/yew-router](https://crates.io/crates/yew-router)\n\nRouters 在单页应用（SPA）中根据 URL 的不同显示不同的页面。当点击一个链接时，Router 在本地设置 URL 以指向应用程序中有效的路由，而不是默认请求一个不同的远程资源。然后 Router 检测到此更改后决定要渲染的内容。\n\n## 核心元素\n\n### Route\n\n包含一个字符串，该字符串表示网址中域名之后的所有内容，还可以选择表示存储在 history api 中的状态。\n\n### RouteService\n\n与浏览器通信以获取和设置路由。\n\n### RouteAgent\n\n拥有一个 RouteService，并用于当路由改变时协调更新，无论更新是来自应用程序自身逻辑还是来自浏览器触发的事件。\n\n### Switch\n\n`Switch` trait 用于在该 trait 的实现者之间转换 `Route`。\n\n### Router\n\nRouter 组件同 `RouterAgent` 进行通信，并将自动把它从 Agent 那里获得的 Routes 解析为 Switches，并通过 `render` 属性暴露该 Switch，该属性允许指定将生成的 Switch 转换为 `HTML` 的方式。\n\n## 如何使用 Router\n\n首先，你要创建一个表征你的应用程序所有状态的类型。请注意，虽然这通常是一个枚举，但也支持结构体，并且你可以在内部嵌套实现了 `Switch` trait 的其他项。\n\n然后你应该为了你创建的类型派生 `Switch`。对于枚举，每一个成员都必须用 `#[to = \"/some/route\"]` 进行标注，如果你使用结构体，则标注必须出现在结构体声明之外。\n\n请注意，由派生宏为 `Switch` 生成的实现，将尝试从头到尾依次创建每个成员，因此，如果任何路由可能与你指定的两个 `to` 标注相匹配，那么第一个会被匹配，第二个将永远不会被尝试。\n\n你还可以在 `#[to = \"\"]` 标注中使用 `{}` 的变体来捕获片段。`{}` 表示捕获文本直到下一个分隔符（根据上下文可能是\"/\"，\"?\"，\"&\" 或 \"\\#\"）。`{*}` 表示捕获文本直到后续字符匹配为止，如果不存在任何字符，则它将匹配任何内容。`{<number>}` 表示捕获文本直到遇到指定数目的分隔符为止（例如：`{2}` 将一直捕获文本直到遇到两个分隔符为止）。\n\n对于具有命名字段的结构体和枚举，你必须在捕获组中指定字段的名称，例如：`{user_name}` 或 `{*:age}`。\n\nSwitch trait 适用于比字符串更结构化的捕获组。你可以指定实现了 `Switch` trait 的任何类型。因此，你可以指定捕获组为 `usize`，并且如果 URL 的捕获部分无法转换为它，则该成员不会被匹配。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/getting-started/build-a-sample-app.mdx",
    "content": "# 第一个简单的 App\n\n首先创建一个二进制项目:\n\n```bash\ncargo new --bin yew-app && cd yew-app\n```\n\n添加 `yew` 到你的依赖库中（[这里](https://docs.rs/yew) 可以查看最新版本的 Yew）\n\n```text title=\"Cargo.toml\"\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nauthors = [\"Yew App Developer <name@example.com>\"]\nedition = \"2018\"\n\n[dependencies]\nyew = { version = \"0.14.3\", features = [\"std_web\"] }\n```\n\n将这份代码复制到你的 `src/main.rs` 文件中:\n\n```rust title=\"src/main.rs\"\nuse yew::prelude::*;\n\nstruct Model {\n    link: ComponentLink<Self>,\n    value: i64,\n}\n\nenum Msg {\n    AddOne,\n}\n\nimpl Component for Model {\n    type Message = Msg;\n    type Properties = ();\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        Self {\n            link,\n            value: 0,\n        }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::AddOne => self.value += 1\n        }\n        true // 指示组件应该重新渲染\n    }\n\n    fn view(&self) -> Html {\n        html! {\n            <div>\n                <button onclick={self.link.callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n                <p>{ self.value }</p>\n            </div>\n        }\n    }\n}\n\nfn main() {\n    yew::initialize();\n    App::<Model>::new().mount_to_body();\n}\n```\n\n这份代码将构建你的称为 `Model` 的 `Component` 根组件，它会显示一个按钮，当你点击它时，`Model` 将会更新自己的状态。特别注意 `main()` 中的 `App::<Model>::new().mount_to_body()`，它会启动你的应用并将其挂载到页面的 `<body>` 标签中。如果你想使用任何动态属性来启动应用程序，则可以使用 `App::<Model>::new().mount_to_body_with_props(..)`。\n\n## 运行你的应用程序!\n\n启动并运行你的应用的最快方式就是使用 [`cargo-web`](https://github.com/koute/cargo-web)。如果你还没有的话，请用 `cargo install cargo-web` 命令来安装这个工具然后通过运行下述命令来构建和启动一个开发服务器：\n\n```bash\ncargo web start\n```\n\n`cargo-web` 将会自动为你添加 `wasm32-unknown-unknown` 作为目标代码，然后构建你的应用，你的应用将默认在 [http://\\[::1\\]:8000](http://[::1]:8000) 被访问。可以通过 `cargo web start --help` 命令来获取更多选项和帮助。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/getting-started/examples.mdx",
    "content": "# 通过例子学习\n\nYew 的 github 项目中就包含了各种各样的示例（这些项目在不同程度的维护中）。我们建议仔细地学习它们, 了解如何使用不同的框架特性. 我们在书中有纰漏和错误的时候也欢迎 pull-requests 和提交 issues ♥️\n\n- [**Todo App（代办事项）\\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/todomvc)\n- [**Todo App（代办事项）\\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/todomvc)\n- [**Custom Components（自定义 Component 组件）**](https://github.com/yewstack/yew/tree/v0.14.0/examples/custom_components)\n- [**Multi-threading \\(Agents\\)（多线程 Agents）\\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/multi_thread)\n- [**Multi-threading \\(Agents\\)（多线程 Agents）\\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/multi_thread)\n- [**Timer Service（计时器）**](https://github.com/yewstack/yew/tree/v0.14.0/examples/timer)\n- [**Nested Components（嵌套 Component 组件）**](https://github.com/yewstack/yew/tree/v0.14.0/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/more/css.mdx",
    "content": "# CSS\n\n&lt;TODO&gt;\n\n对适当的 CSS 支持的提案可以在这里找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/more/debugging.mdx",
    "content": "# Debugging\n\n## Panics\n\nPlease use the [`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook) crate for nicer stacktraces with Rust symbols. Note, that it is not compatible with apps built with `cargo-web`.\n\n## Console Logging\n\nIn general, Wasm web apps are able to interact with Browser APIs, and the `console.log` api is no exception. There are a few options available:\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\nThis crate integrates with the familiar Rust `log` crate:\n\n```rust\n// setup\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n}\n\n// usage\nlog::info!(\"Update: {:?}\", msg);\n```\n\n### **\\`\\`**[**`ConsoleService`**](https://docs.rs/yew/0.13.2/yew/services/console/struct.ConsoleService.html)**\\`\\`**\n\nThis service is included within yew and is available when the `\"services\"` feature is enabled:\n\n```rust\n// usage\nConsoleService::info(format!(\"Update: {:?}\", msg).as_ref());\n```\n\n## Source Maps\n\nThere is currently no first-class support for source maps for Rust / Wasm web apps. This, of course, is subject to change. If this is no longer true or if progress is made, please suggest a change!\n\n### Latest Info\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) don’t support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/more/roadmap.mdx",
    "content": "---\ndescription: Yew 框架规划功能的路线图\n---\n\n# 路线图\n\n## `v1.0.0`\n\n### 规划中的功能\n\n- 标记 key 的列表项：[https://github.com/yewstack/yew/issues/479](https://github.com/yewstack/yew/issues/479)\n- 路由：[https://github.com/yewstack/yew_router](https://github.com/yewstack/yew_router)\n\n### 生产环境准备\n\n- 浏览器兼容性\n- 提高 Yew 框架的测试覆盖率\n- 增加性能基准测试：[https://github.com/yewstack/yew/issues/5](https://github.com/yewstack/yew/issues/5)\n\n### 指南\n\n- 最佳实践：[https://yew.rs/optimizations](https://yew.rs/optimizations)\n- 端到端教程\n- Futures / 并发\n- CSS / 样式\n- 测试\n- 状态管理\n\n## 未来\n\n### 潜在功能\n\n- 服务端渲染：[https://github.com/yewstack/yew/issues/41](https://github.com/yewstack/yew/issues/41)\n- 组件库：[https://github.com/yewstrap/yewstrap](https://github.com/yewstrap/yewstrap)\n- 代码分割：[https://github.com/yewstack/yew/issues/599](https://github.com/yewstack/yew/issues/599)\n- 允许不同的虚拟 DOM 后端：[https://github.com/yewstack/yew/issues/482](https://github.com/yewstack/yew/issues/482)\n- 反思 Services：[https://github.com/yewstack/yew/issues/364](https://github.com/yewstack/yew/issues/364)\n- 成熟的工具包：[https://github.com/yewstack/yewtil](https://github.com/yewstack/yewtil)\n- HTML 模板备选方案：[https://github.com/yewstack/yew/issues/438](https://github.com/yewstack/yew/issues/438)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21/more/testing.mdx",
    "content": "---\ndescription: 测试你的应用程序\n---\n\n# 测试\n\n&lt;TODO&gt;\n\n## Rust WebDriving\n\n使用 Rust 以编程方式驱动 UI 集成测试，[fantoccini](https://crates.io/crates/fantoccini) 是一个推荐的选择。它允许你通过使用 CSS 选择器来查找特定的元素，然后对它们执行特定的操作，例如输入文本，点击按钮，或等待特定时间以使客户端代码执行（例如等待一个网络请求完成并导致 UI 改变），来测试你的网站。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.21.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.21\",\n    \"description\": \"The label for version 0.21\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Using Basic Web Technologies In Yew\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew's Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may needin one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/children.mdx",
    "content": "---\ntitle: '子组件'\n---\n\n:::caution\n\n检查和操作 `Children` 往往会导致应用程序中令人惊讶且难以解释的行为。这可能导致边缘情况，并且通常不会产生预期的结果。如果您尝试操作 `Children`，则应考虑其他方法。\n\nYew 支持将 `Html` 用作子组件属性的类型。如果您不需要 `Children` 或 `ChildrenRenderer`，则应使用 `Html` 作为子组件。它没有 `Children` 的缺点，并且性能开销较低。\n\n:::\n\n## 通用用法\n\n*大多数情况下，*当允许组件具有子组件时，您不关心组件具有的子组件的类型。在这种情况下，下面的示例就足够了。\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## 高级用法\n\n### 类型化子组件\n\n在您希望将一种类型的组件作为子组件传递给您的组件的情况下，您可以使用 `yew::html::ChildrenWithProps<T>`。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## 带有属性的嵌套子组件\n\n如果包含组件对其子组件进行了类型化，则可以访问和更改嵌套组件的属性。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 枚举类型的子组件\n\n当然，有时您可能需要将子组件限制为几种不同的组件。在这些情况下，您必须更深入地了解 Yew。\n\n这里使用 [`derive_more`](https://github.com/JelteF/derive_more) 来提供更好的人机工程学。如果您不想使用它，您可以为每个变体手动实现 `From`。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 现在，我们实现 `Into<Html>`，以便 yew 知道如何渲染 `Item`。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### 可选类型的子组件\n\n您还可以具有特定类型的单个可选子组件：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... 页面内容\n            </div>\n        }\n    }\n}\n\n// 页面组件可以选择是否附带侧边栏：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // 附带侧边栏的页面\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // 不附带侧边栏的页面\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## 进一步阅读\n\n- 有关此模式的真实示例，请查阅 yew-router 的源代码。有关更高级的示例，请查看 yew 存储库中的[相关示例清单](https://github.com/yewstack/yew/tree/master/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '工作原理'\ndescription: '关于框架的底层细节'\n---\n\n# 底层库的内部细节\n\n## `html!` 宏的内部\n\n`html!` macro 会将使用类似 HTML 的自定义语法编写的代码转换为有效的 Rust 代码。使用这个宏对于开发 Yew 应用程序并不是必需的，但是是推荐的。这个宏生成的代码使用了 Yew 的公共库 API，如果你愿意的话，可以直接使用。请注意，有些方法是有意未记录的，以避免意外的误用。随着 `yew-macro` 的每次更新，生成的代码将会更加高效，并且可以处理任何破坏性的更改，而不需要对 `html!` 语法进行很多（如果有的话）修改。\n\n由于 `html!` 宏允许您以声明式的风格编写代码，因此您的 UI 布局代码将与为页面生成的 HTML 非常相似。随着您的应用程序变得更加交互式，您的代码库变得更大，这种方式变得越来越有用。与手动编写所有操作 DOM 的代码相比，宏会为您处理好这一切。\n\n使用 `html!` 宏可能会让人感到非常神奇，但它并没有什么可隐藏的。如果您对它的工作原理感到好奇，可以尝试展开您程序中的 `html!` 宏调用。有一个有用的命令叫做 `cargo expand`，它允许您查看 Rust 宏的展开。`cargo expand` 并不是默认随 `cargo` 一起提供的，所以如果您还没有安装它，您需要使用 `cargo install cargo-expand` 来安装它。[Rust-Analyzer](https://rust-analyzer.github.io/) 也提供了一种[从 IDE 中获取宏输出的机制](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)。\n\n`html!` 宏的输出通常非常简洁！这是一个特性：机器生成的代码有时可能会与应用程序中的其他代码冲突。为了防止问题，`proc_macro` 遵循了“卫生”规则。一些例子包括：\n\n1. 为了确保正确引用 Yew 包，宏生成的代码中使用 `::yew::<module>`，而不是直接使用 `yew::<module>`。这也是为什么调用 `::alloc::vec::Vec::new()` 而不是直接调用 `Vec::new()`。\n2. 由于可能存在 trait 方法名称冲突，使用 `<Type as Trait>` 来确保我们使用的是正确的 trait 成员。\n\n## 什么是虚拟 DOM？\n\nDOM（\"文档对象模型\"）是由浏览器管理的 HTML 内容的表示。\"虚拟\" DOM 只是 DOM 的一个内存中的副本。管理虚拟 DOM 会导致更高的内存开销，但可以通过避免或延迟使用浏览器 API 来实现批处理和更快的读取。\n\n在内存中拥有 DOM 的副本对于促进使用声明式 UI 的库是有帮助的。与需要特定代码来描述如何根据用户事件修改 DOM 不同，库可以使用一种通用的方法来进行 DOM \"diffing\"。当 Yew 组件更新并希望更改其呈现方式时，Yew 库将构建虚拟 DOM 的第二个副本，并直接将其与镜像当前屏幕上的内容的虚拟 DOM 进行比较。两者之间的 \"diff\"（差异）可以分解为增量更新，并与浏览器 API 一起应用。一旦更新应用，旧的虚拟 DOM 副本将被丢弃，新的副本将被保存以供将来的差异检查。\n\n这种 \"diff\" 算法可以随着时间的推移进行优化，以提高复杂应用程序的性能。由于 Yew 应用程序是通过 WebAssembly 运行的，我们相信 Yew 在未来采用更复杂的算法方面具有竞争优势。\n\nYew 的虚拟 DOM 与浏览器 DOM 不完全一一对应。它还包括用于组织 DOM 元素的 \"列表\" 和 \"组件\"。列表可以简单地是元素的有序列表，但也可以更强大。通过为每个列表元素添加 \"key\" 注解，应用程序开发人员可以帮助 Yew 进行额外的优化，以确保在列表更改时，计算差异更新所需的工作量最小。同样，组件提供了自定义逻辑，指示是否需要重新渲染，以帮助提高性能。\n\n## Yew 调度器和组件范围的事件循环\n\n_贡献文档 - 深入解释 `yew::scheduler` 和 `yew::html::scope` 的工作原理_\n\n## 进一步阅读\n\n- [Rust 手册中关于宏的更多信息](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` 的更多信息](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` 的 API 文档](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/immutable.mdx",
    "content": "---\ntitle: '不可变类型'\ndescription: 'Yew 的不可变数据结构'\n---\n\n## 什么是不可变类型？\n\n这些类型是您可以实例化但永远不会更改值的类型。为了更新值，您必须实例化一个新值。\n\n## 为什么使用不可变类型？\n\n与 React 一样，属性是从祖先传播到子代的。这意味着属性在每个组件更新时必须存在。这就是为什么属性应该——理想情况下——很容易克隆。为了实现这一点，我们通常将事物包装在 `Rc` 中。\n\n不可变类型非常适合保存属性的值，因为它们可以在从组件传递到组件时以很低的成本克隆。\n\n## 常见的不可变类型\n\nYew 推荐使用来自 `implicit-clone` crate 的以下不可变类型：\n\n- `IString`（在 Yew 中别名为 `AttrValue`）- 用于字符串而不是 `String`\n- `IArray<T>` - 用于数组/向量而不是 `Vec<T>`\n- `IMap<K, V>` - 用于映射而不是 `HashMap<K, V>`\n\n这些类型是引用计数（`Rc`）或静态引用，使它们的克隆成本非常低。\n\n## 进一步阅读\n\n- [不可变示例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '优化 & 最佳实践'\nsidebar_label: Optimizations\ndescription: '让您的应用程序获得最佳性能'\n---\n\n## 使用智能指针\n\n**注意：如果您对本节中使用的某些术语感到困惑，Rust 手册中有一个有用的[关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)。**\n\n为了避免在重新渲染时克隆大量数据以创建 props，我们可以使用智能指针，只克隆对数据的引用而不是数据本身。如果您在 props 和子组件中传递与相关数据的引用而不是实际数据，您可以避免在需要修改数据的子组件中克隆任何数据，您可以使用 `Rc::make_mut` 来克隆并获得要更改的数据的可变引用。\n\n这在 `Component::changed` 中带来了更多好处，可以确定 prop 更改是否需要组件重新渲染。这是因为可以比较指针地址（即数据存储在机器内存中的位置）而不是数据的值；如果两个指针指向相同的数据，则它们指向的数据的值必须相同。请注意，反之可能不成立！即使两个指针地址不同，底层数据仍可能相同 - 在这种情况下，您应该比较底层数据。\n\n要进行此比较，您需要使用 `Rc::ptr_eq` 而不仅仅使用 `PartialEq`（在使用相等运算符 `==` 比较数据时自动使用）。Rust 文档有关于 `Rc::ptr_eq` 的[更多细节](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\n这种优化对于不实现 `Copy` 的数据类型最有用。如果您可以廉价地复制数据，则没有必要将其放在智能指针后面。对于可能是数据密集型的结构，如 `Vec`、`HashMap` 和 `String`，使用智能指针可能会带来性能改进。\n\n如果值从不被子组件更新，则此优化效果最佳，如果父组件很少更新，则效果更佳。这使得 `Rc<_>` 是在纯组件中包装属性值的一个不错的选择。\n\n但是，必须注意，除非您需要在子组件中自己克隆数据，否则这种优化不仅是无用的，而且还增加了不必要的引用计数成本。Yew 中的 props 已经是引用计数的，内部不会发生数据克隆。\n\n## 渲染函数\n\n出于代码可读性的原因，将 `html!` 的部分重复代码迁移到专门分割出来的函数中通常是有意义的。这不仅使您的代码更易读，减少了代码缩进，而且还鼓励良好的设计模式——特别是围绕构建可组合应用程序，这些函数可以在多个地方调用，从而减少代码量。\n\n## 纯组件\n\n纯组件是不会改变其状态的组件，只显示内容并将消息传播到普通的可变组件。它们与视图函数的不同之处在于，它们可以在 `html!` 宏中使用组件语法（`<SomePureComponent />`）而不是表达式语法（`{some_view_function()}`），并且根据其实现，它们可以被记忆化（这意味着一旦调用函数，其值就会被“保存”，因此如果多次使用相同的参数调用它，则不必重新计算其值，只需从第一个函数调用返回保存的值）- 防止相同的 props 重新渲染。Yew 在内部比较 props，因此仅在 props 更改时重新渲染 UI。\n\n## 使用工作区减少编译时间\n\nYew 的最大缺点是编译所需的时间很长。编译项目所需的时间似乎与传递给 `html!` 宏的代码数量有关。对于较小的项目，这似乎不是什么问题，但对于较大的应用程序，将代码拆分到多个 crate 中以最小化编译器为应用程序所做的工作量是有意义的。\n\n一种可能的方法是使您的主 crate 处理路由/页面选择，然后为每个页面创建一个不同的 crate，其中每个页面可以是不同的组件或只是生成 `Html` 的大函数。存储在包含应用程序不同部分的 crate 之间的代码可以存储在项目依赖的单独 crate 中。在最理想的情况下，您从在每次编译时重新构建所有代码到仅重新构建主 crate 和一个页面 crate。在最坏的情况下，如果您在“common” crate 中编辑了某些内容，您将回到起点：编译依赖于该常用共享 crate 的所有代码，这可能是其他所有内容。\n\n如果您的主 crate 太重，或者您想快速迭代一个深度嵌套的页面（例如。在另一个页面上渲染的页面），您可以使用示例 crate 创建主页面的简化实现，并额外渲染您正在处理的组件。\n\n## 减小二进制文件大小\n\n- 优化 Rust 代码\n- `cargo.toml`（定义发布配置文件）\n- 使用 `wasm-opt` 优化 wasm 代码\n\n**注意：有关减小二进制文件大小的更多信息，请参阅[Rust Wasm 手册](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)。**\n\n### Cargo.toml\n\n可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用设置来配置发布构建为更小。\n\n```toml, title=Cargo.toml\n[profile.release]\n# 让二进制文件尺寸更小些\npanic = 'abort'\n# 优化整个代码库（优化更好，但构建速度也会更慢）\ncodegen-units = 1\n# 优化尺寸（更激进的做法）\nopt-level = 'z'\n# 优化尺寸\n# opt-level = 's'\n# 使用程序整体分析时进行链接时优化\nlto = true\n```\n\n### 开发版 Cargo 配置\n\n您还可以从 Rust 和 cargo 的实验性开发版功能中获得额外的好处。要使用 `trunk` 的开发版工具链，请设置 `RUSTUP_TOOLCHAIN=\"nightly\"` 环境变量。然后，您可以在 `.cargo/config.toml` 中配置不稳定的 rustc 功能。请参考[不稳定功能]的文档，特别是关于[`build-std`]和[`build-std-features`]的部分，以了解配置。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# 需要 rust-src 组件。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不稳定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n开发版 Rust 编译器可能包含错误，例如[这个例子](https://github.com/yewstack/yew/issues/2696)，需要偶尔关注和调整。请谨慎使用这些实验性选项。\n:::\n\n### wasm-opt\n\n此外，可以优化 `wasm` 代码的大小。\n\nRust Wasm 手册中有关于减小 Wasm 二进制文件大小的部分：[缩小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用 `wasm-pack`，默认情况下会优化发布构建中的 `wasm` 代码\n- 直接在 `wasm` 文件上使用 `wasm-opt`\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 在 yew/examples/ 中 'minimal' 示例的构建大小\n\n注意：`wasm-pack` 结合了 Rust 和 Wasm 代码的优化。在此示例中，`wasm-bindgen` 未经任何 Rust 大小优化。\n\n| 工具链                      | 大小  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## 进一步阅读\n\n- [Rust 手册中关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm 手册中关于减小二进制文件大小的信息](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust 配置文件的文档](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen 项目](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/portals.mdx",
    "content": "---\ntitle: '传送门 (Portals)'\ndescription: '将内容渲染到 DOM 树外的节点'\n---\n\n## 什么是 Portal？\n\n传送门 (Portal) 提供了一种将子元素渲染到父组件的 DOM 层次结构之外的 DOM 节点的方法。`yew::create_portal(child, host)` 返回一个 `Html` 值，它将 `child` 渲染为 `host` 元素的子元素，而不是在其父组件的层次结构下。\n\n## 用法\n\n传送门的典型用途包括模态对话框和悬停卡片，以及更多技术应用，例如控制元素的 [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) 的内容，将样式表附加到周围文档的 `<head>` 中，以及在 `<svg>` 的中央 `<defs>` 元素中收集引用的元素。\n\n请注意，`yew::create_portal` 是一个低级构建块。库应该使用它来实现更高级的 API，然后应用程序可以使用这些 API。例如，这里是一个简单的模态对话框，它将其 `children` 渲染到 `yew` 之外的一个元素中，该元素由 `id=\"modal_host\"` 标识。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## 事件处理\n\n传送门内部元素上发出的事件遵循虚拟 DOM 冒泡。也就是说，如果传送门被渲染为元素的子元素，那么该元素上的事件监听器将捕获从传送门内部分发出的事件，即使传送门将其内容渲染在实际 DOM 中的不相关位置。\n\n这使开发人员无需关心他们使用的组件是使用传送门实现的还是没有使用传送门实现的。无论如何，其子元素上触发的事件都会冒泡。\n\n已知问题是，从传送门到 **关闭** 的 shadow root 的事件将被分发两次，一次针对 shadow root 内部的元素，一次针对宿主元素本身。请记住，**打开** 的 shadow root 可以正常工作。如果这影响到您，请随时提交一个错误报告。\n\n## 进一步阅读\n\n- [传送门示例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: '服务端渲染'\ndescription: '在服务端渲染 Yew 组件。'\n---\n\n# 服务端渲染 (Server-Side Rendering)\n\n默认情况下，Yew 组件在客户端渲染。当用户访问一个网站时，服务器会发送一个骨架 HTML 文件，不包含任何实际内容，以及一个 WebAssembly 包给浏览器。所有内容都由 WebAssembly 包在客户端渲染。这被称为客户端渲染。\n\n这种方法对于大多数网站来说都是有效的，但有一些注意事项：\n\n1. 用户在整个 WebAssembly 包下载并完成初始渲染之前将看不到任何内容。这可能会导致在缓慢的网络上用户体验不佳。\n2. 一些搜索引擎不支持动态渲染的网页内容，而那些支持的搜索引擎通常会将动态网站排名较低。\n\n为了解决这些问题，我们可以在服务端渲染我们的网站。\n\n## 工作原理\n\nYew 提供了一个 `ServerRenderer` 来在服务端渲染页面。\n\n要在服务端渲染 Yew 组件，您可以使用 `ServerRenderer::<App>::new()` 创建一个渲染器，并调用 `renderer.render().await` 将 `<App />` 渲染为一个 `String`。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// 我们在使用 `flavor = \"current_thread\"` 以保证这个示例可以在 CI 中的 WASM 环境运行,\n// 如果你希望使用多线程的话，可以使用默认的 `#[tokio::main]` 宏\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // 打印: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## 组件生命周期\n\n与客户端渲染不同，组件的生命周期在服务端渲染时会有所不同。\n\n在组件成功第一次渲染为 `Html` 之前，除了 `use_effect` (和 `use_effect_with`) 之外的所有钩子都会正常工作。\n\n:::caution 浏览器接口不可用！\n\n浏览器相关的接口，如 `web_sys`，在组件在服务端渲染时是不可用的。如果您尝试使用它们，您的应用程序将会崩溃。您应该将需要这部分逻辑隔离在 `use_effect` 或 `use_effect_with` 中，因为在服务端渲染时它们无法也不应当执行。\n\n:::\n\n:::danger 结构化组件\n\n尽管可以在服务端渲染时使用结构化组件，但是在客户端安全逻辑（如函数组件的 `use_effect` 钩子）和生命周期事件之间没有明确的边界，并且生命周期事件的调用顺序与客户端不同。\n\n此外，结构化组件将继续接受消息，直到所有子组件都被渲染并调用了 `destroy` 方法。开发人员需要确保不会将可能传递给组件的消息链接到调用浏览器接口的逻辑。\n\n在设计支持服务端渲染的应用程序时，请尽量使用函数组件，除非您有充分的理由不这样做。\n\n:::\n\n## 服务端渲染期间的数据获取\n\n数据获取是服务端渲染和水合（hydration）期间的难点之一。\n\n传统做法中，当一个组件渲染时，它会立即可用（输出一个虚拟 DOM 以进行渲染）。当组件不需要获取任何数据时，这种方式是有效的。但是如果组件在渲染时想要获取一些数据会发生什么呢？\n\n过去，Yew 没有机制来检测组件是否仍在获取数据。数据获取客户端负责实现一个解决方案，以检测在初始渲染期间请求了什么，并在请求完成后触发第二次渲染。服务器会重复这个过程，直到在返回响应之前没有在渲染期间添加更多的挂起请求。\n\n这不仅浪费了 CPU 资源，因为重复渲染组件，而且数据客户端还需要提供一种方法，在水合过程中使在服务端获取的数据可用，以确保初始渲染返回的虚拟 DOM 与服务端渲染的 DOM 树一致，这可能很难实现。\n\nYew 采用了一种不同的方法，通过 `<Suspense />` 来解决这个问题。\n\n`<Suspense />` 是一个特殊的组件，当在客户端使用时，它提供了一种在组件获取数据（挂起）时显示一个回退 UI 的方法，并在数据获取完成后恢复到正常 UI。\n\n当应用程序在服务端渲染时，Yew 会等待组件不再挂起，然后将其序列化到字符串缓冲区中。\n\n在水合过程中，`<Suspense />` 组件中的元素保持未水合状态，直到所有子组件不再挂起。\n\n通过这种方法，开发人员可以轻松构建一个准备好进行服务端渲染的、与客户端无关的应用程序，并进行数据获取。\n\n## 渲染 `<head>` 标签\n\nSSR 中的一个常见需求是渲染动态 `<head>` 内容（例如 `<title>`、`<meta>`），使爬虫和社交预览在首次加载时能看到正确的元数据。\n\n`ServerRenderer` 只渲染组件树（通常对应文档的 body 部分），无法访问 `<head>`。因此，head 标签必须**在服务端、Yew 之外**生成，并在发送给客户端之前拼接到 HTML 模板中。\n\n[`ssr_router` 示例](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) 演示了这一模式：服务端从请求 URL 识别路由，生成适当的 `<title>` 和 `<meta>` 标签，并将它们注入到 Trunk 生成的 `index.html` 的 `</head>` 之前。\n\n:::info\n\n如需完全兼容 SSR 的第三方解决方案，请使用 [Bounce 的 `<Helmet/>` 组件](https://docs.rs/bounce/latest/bounce/helmet/index.html)。\n\n:::\n\n## SSR 水合（SSR Hydration）\n\n水合是将 Yew 应用程序连接到服务端生成的 HTML 文件的过程。默认情况下，`ServerRender` 打印可水合的 HTML 字符串，其中包含额外的信息以便于水合。当调用 `Renderer::hydrate` 方法时，Yew 不会从头开始渲染，而是将应用程序生成的虚拟 DOM 与服务器渲染器生成的 HTML 字符串进行协调。\n\n:::caution\n\n要成功对由 `ServerRenderer` 创建的 HTML 标记进行水合，客户端必须生成一个虚拟 DOM 布局，它与用于 SSR 的布局完全匹配，包括不包含任何元素的组件。如果您有任何只在一个实现中有用的组件，您可能希望使用 `PhantomComponent` 来填充额外组件的位置。\n:::\n\n:::warning\n\n只有在浏览器初始渲染 SSR 输出（静态 HTML）后，真实 DOM 与预期 DOM 匹配时，水合才能成功。如果您的 HTML 不符合规范，水合可能会失败。浏览器可能会更改不正确的 HTML 的 DOM 结构，导致实际 DOM 与预期 DOM 不同。例如，[如果您有一个没有 `<tbody>` 的 `<table>`，浏览器可能会向 DOM 添加一个 `<tbody>`](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## 水合期间的组件生命周期\n\n在水合期间，组件在创建后安排了 2 次连续的渲染。任何效果都是在第二次渲染完成后调用的。确保您的组件的渲染函数没有副作用是很重要的。它不应该改变任何状态或触发额外的渲染。如果您的组件当前改变状态或触发额外的渲染，请将它们移动到 `use_effect` 钩子中。\n\n在水合过程中，可以使用结构化组件进行服务端渲染，视图函数将在渲染函数之前被调用多次。直到调用渲染函数之前，DOM 被认为是未连接的，您应该防止在调用 `rendered()` 方法之前访问渲染节点。\n\n## 示例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // 对 body 元素下的所有内容进行水合，并移除尾部元素（如果有）。\n    renderer.hydrate();\n}\n```\n\n示例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n示例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## 单线程模式\n\nYew 支持以单线程进行服务端渲染，通过 `yew::LocalServerRenderer`。这种模式适用于像 WASI 这样的单线程环境。\n\n```rust\n// 使用 `wasm32-wasip1` 或 `wasm32-wasip2` 目标构建。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n示例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n如果您使用 `wasm32-unknown-unknown` 目标构建 SSR 应用程序，您可以使用 `not_browser_env` 功能标志来禁用 Yew 内部对特定于浏览器的 API 的访问。这在像 Cloudflare Worker 这样的无服务器平台上非常有用。\n:::\n\n:::caution\n\n服务端渲染目前是实验性的。如果您发现了一个 bug，[请在 GitHub 反馈](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回调函数 (Callbacks)'\n---\n\n## 回调函数 (Callbacks)\n\n回调函数是用于在 Yew 中与服务、代理和父组件进行通信的。在内部，它们的类型只是 `Fn` 包装在 `Rc` 中，以允许它们被克隆。\n\n它们有一个 `emit` 函数，该函数以其 `<IN>` 类型作为参数，并将其转换为其目标期望的消息。如果父组件中的回调函数作为 props 提供给子组件，子组件可以在其 `update` 生命周期钩子中调用回调函数的 `emit` 函数，以将消息发送回其父组件。在 `html!` 宏中作为 props 提供的闭包或函数会自动转换为回调函数。\n\n一个简单的回调函数的使用可能如下所示：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\n这个函数传递给 `callback` 必须始终带有一个参数。例如，`onclick` 处理程序需要一个接受 `MouseEvent` 类型参数的函数。然后处理程序可以决定应该发送什么类型的消息给组件。这个消息无条件地被安排在下一个更新循环中。\n\n如果你需要一个回调函数，它可能不需要引起更新，请使用 `batch_callback`。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 相关示例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高阶组件'\n---\n\n在一些情况下，结构组件不直接支持某些功能（例如 Suspense），或者使用某些功能需要大量的样板代码（例如 Context）。\n\n在这些情况下，建议创建高阶组件的函数组件。\n\n## 高阶组件定义\n\n高阶组件是不添加任何新 HTML 的组件，只是包装其他组件以提供额外功能。\n\n### 示例\n\n对 Context (上下文) 挂钩并将其传递给结构组件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '简介'\ndescription: 'Yew 中的组件'\n---\n\n## 什么是组件？\n\n组件是 Yew 的构建块。它们管理内部状态并可以将元素渲染到 DOM 中。通过为类型实现 `Component` trait 来创建组件。\n\n## 编写组件标记\n\nYew 使用虚拟 DOM 将元素渲染到 DOM 中。虚拟 DOM 树可以通过使用 `html!` 宏来构建。`html!` 使用的语法类似于 HTML，但并不相同。规则也更严格。它还提供了诸如条件渲染和使用迭代器渲染列表等超能力。\n\n:::info\n[了解更多关于 `html!` 宏，如何使用它以及它的语法](concepts/html/introduction.mdx)\n:::\n\n## 将数据传递给组件\n\nYew 组件使用 _props_ 在父组件和子组件之间通信。父组件可以将任何数据作为 props 传递给其子组件。Props 类似于 HTML 属性，但可以将任何 Rust 类型作为 props 传递。\n\n:::info\n[了解更多关于 props 的内容](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n对于除了父/子通信之外的其他通信，请使用 [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命周期'\ndescription: '组件及其生命周期钩子'\n---\n\n`Component` trait 有许多方法需要实现；Yew 会在组件的生命周期的不同阶段调用这些方法。\n\n## 生命周期\n\n:::important 改进文档\n`为文档做贡献：` [添加定制生命周期的组件示例](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命周期方法\n\n### Create\n\n当组件被创建时，它会从其父组件接收属性，并存储在传递给 `create` 方法的 `Context<Self>` 中。这些属性可以用来初始化组件的状态，而 \"link\" 可以用来注册回调或向组件发送消息。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体实现\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法允许您描述组件应该如何呈现到 DOM 中。使用 Rust 函数编写类似 HTML 的代码可能会变得非常混乱，因此 Yew 提供了一个名为 `html!` 的宏，用于声明 HTML 和 SVG 节点（以及将属性和事件监听器附加到它们）以及一种方便的方法来渲染子组件。这个宏在某种程度上类似于 React 的 JSX（除了编程语言的差异）。一个不同之处是 Yew 提供了一种类似 Svelte 的属性的简写语法，其中您可以只写 `{onclick}`，而不用写 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n就使用上的说明，请查看 [html! 指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 组件生命周期方法在 `view` 被调用并且 Yew 已经将结果渲染到 DOM 中后调用，但在浏览器刷新页面之前。当您想要执行只能在组件渲染元素后完成的操作时，此方法非常有用。还有一个名为 `first_render` 的参数，可以用来确定此函数是在第一次渲染时调用，还是在后续渲染时调用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n请注意，此生命周期方法不需要实现，并且默认情况下不会执行任何操作。\n:::\n\n### Update\n\n与组件的通信主要通过消息进行，这些消息由 `update` 生命周期方法处理。这允许组件根据消息更新自身，并确定是否需要重新渲染自身。消息可以由事件监听器、子组件、Agents、Services 或 Futures 发送。\n\n下面是 `update` 的一个实现示例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 重新渲染\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体实现\n        }\n    }\n}\n```\n\n### Changed\n\n组件可能会被其父组件重新渲染。当这种情况发生时，它们可能会接收新的属性并需要重新渲染。这种设计通过仅更改属性的值来促进父子组件之间的通信。当属性更改时，有一个默认实现会重新渲染组件。\n\n### Destroy\n\n组件从 DOM 中卸载后，Yew 会调用 `destroy` 生命周期方法；如果您需要在组件被销毁之前执行清理操作，这是必要的。此方法是可选的，默认情况下不执行任何操作。\n\n### 无限循环\n\n无限循环在 Yew 的生命周期方法中是可能的，但只有在尝试在每次渲染后更新相同的组件时，当该更新还要求重新渲染组件时才会发生。\n\n下面是一个简单的示例：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // 我们总是请求在任何消息上重新渲染\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // 无论渲染什么都不重要\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // 请求使用此新消息更新组件\n        ctx.link().send_message(());\n    }\n}\n```\n\n让我们看看这里发生了什么：\n\n1. 使用 `create` 函数创建组件。\n2. 调用 `view` 方法，以便 Yew 知道要渲染到浏览器 DOM 中的内容。\n3. 调用 `rendered` 方法，使用 `Context` 链接安排更新消息。\n4. Yew 完成后渲染阶段。\n5. Yew 检查已安排的事件，并看到更新消息队列不为空，因此处理消息。\n6. 调用 `update` 方法，返回 `true` 表示发生了变化，组件需要重新渲染。\n7. 跳回到第 2 步。\n\n您仍然可以在 `rendered` 方法中安排更新，这通常是有用的，但是在这样做时，请考虑您的组件将如何终止此循环。\n\n## 关联类型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 类型用于在事件发生后向组件发送消息；例如，您可能希望在用户单击按钮或向下滚动页面时执行某些操作。因为组件通常需要响应多个事件，所以 `Message` 类型通常是一个枚举，其中每个变体都是要处理的事件。\n\n在组织代码库时，将 `Message` 类型的定义包含在定义组件的同一模块中是明智的。您可能会发现采用一致的命名约定来命名消息类型很有帮助。一个选项（尽管不是唯一的选项）是将类型命名为 `ComponentNameMsg`，例如，如果您的组件名为 `Homepage`，则可以将类型命名为 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示从其父组件传递给组件的信息。此类型必须实现 `Properties` trait（通常通过派生它）并可以指定某些属性是必需的还是可选的。在创建和更新组件时使用此类型。在组件的模块中创建一个名为 `Props` 的结构体，并将其用作组件的 `Properties` 类型是一种常见做法。通常将 \"properties\" 缩写为 \"props\"。由于 props 是从父组件传递下来的，因此应用程序的根组件通常具有 `Properties` 类型为 `()`。如果要为根组件指定属性，请使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多关于属性的信息](./properties)\n:::\n\n## 生命周期上下文\n\n所有组件生命周期方法都接受一个上下文对象。此对象提供了对组件作用域的引用，允许向组件发送消息并传递给组件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '属性 (Props)'\ndescription: '父子组件通信'\n---\n\n属性 (Properties) 使子组件和父组件之间能够进行通信。每个组件都有一个关联的属性类型，用于描述从父组件传递下来的内容。理论上，这可以是任何实现了 `Properties` 特性的类型，但实际上，它应该是一个结构体，其中每个字段代表一个属性。\n\n## 派生宏\n\n无需自己实现 `Properties` 特性，我们可以用 `#[derive(Properties)]` 来自动生成实现。派生 `Properties` 的类型也必须实现 `PartialEq`。\n\n### 字段属性\n\n在派生 `Properties` 时，默认情况下所有字段都是必需的。以下属性允许您为属性提供初始值，除非它们被设置为另一个值。\n\n:::tip\n属性不会在 Rustdoc 生成的文档中显示。您的属性的文档字符串应该说明一个属性是否是可选的，以及它是否有一个特殊的默认值。\n:::\n\n#### `#[prop_or_default]`\n\n使用字段类型的默认值使用 `Default` 特性来初始化属性值。\n\n#### `#[prop_or(value)]`\n\n使用 `value` 来初始化属性值。`value` 可以是返回字段类型的任何表达式。例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。\n\n#### `#[prop_or_else(function)]`\n\n调用 `function` 来初始化属性值。`function` 应该具有签名 `FnMut() -> T`，其中 `T` 是字段类型。\n\n## `PartialEq`\n\n`Properties` 需要实现 `PartialEq`。这样，Yew 才能比较它们，以便在它们发生变化时调用 `changed` 方法。\n\n## 使用 Properties 的性能开销\n\n内部属性是基于引用计数的指针存储的。这意味着只有一个指针被传递到组件树中的属性，以避免克隆整个属性所带来的昂贵性能开销。\n\n:::tip\n使用 `AttrValue`，这是我们提供的自定义属性值类型，这样就可以不用 String 或其他类似的需要克隆的类型。\n:::\n\n## 示例\n\n```rust\nuse yew::Properties;\n/// 从 virtual_dom 中导入 AttrValue\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标\n    href: AttrValue,\n    /// 还要注意我们使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 链接的颜色，默认为 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值为 None，则视图函数不会指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 当视图函数没有指定活动时，默认为 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n该宏使用与结构体表达式相同的语法，只是您不能使用属性或基本表达式 (`Foo { ..base }`)。类型路径可以直接指向属性 (`path::to::Props`)，也可以指向组件的关联属性 (`MyComp::Properties`)。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标\n    href: AttrValue,\n    /// 还要注意我们使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 链接的颜色，默认为 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值为 None，则视图函数不会指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 当视图函数没有指定活动时，默认为 true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// 注意此函数接收 href 和 text 作为 String\n    /// 我们可以使用 `AttrValue::from` 将其转换为 `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '引用 (Refs)'\ndescription: '实现越界 DOM 访问'\n---\n\n`ref` 关键字可以在任何 HTML 元素或组件中使用，以获取附加到该元素的 DOM `Element`。这可以用于在 `view` 生命周期方法之外对 DOM 进行更改。\n\n这对于获取 canvas 元素或滚动到页面的不同部分很有用。例如，在组件的 `rendered` 方法中使用 `NodeRef` 允许您在从 `view` 渲染后对 canvas 元素进行绘制调用。\n\n语法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 相关示例\n\n- [节点引用](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: '作用域'\ndescription: '组件的作用域'\n---\n\n## 组件的 `Scope<_>` 接口\n\n`Scope` 是通过消息创建回调并更新自身的机制。我们通过在传递给组件的上下文对象上调用 `link()` 来获得对它的引用。\n\n### `send_message`\n\n这个函数可以向组件发送消息。消息由 `update` 方法处理，该方法确定组件是否应重新渲染。\n\n### `send_message_batch`\n\n这个函数可以同时向组件发送多个消息。这类似于 `send_message`，但是如果任何消息导致 `update` 方法返回 `true`，则组件将在处理完批处理中的所有消息后重新渲染。\n\n如果给定的参数向量为空，则此函数不执行任何操作。\n\n### `callback`\n\n创建一个回调，当执行时将向组件发送消息。在内部，它将使用提供的闭包返回的消息调用 `send_message`。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // 创建一个接受一些文本并将其作为 `Msg::Text` 消息变体发送到组件的回调。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上一行是多余的冗长，为了更清晰，可以简化为这样：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // 将 `Msg::Text(\"Hello World!\")` 发送到组件。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // 在这里放置 HTML\n        }\n    }\n}\n```\n\n### `batch_callback`\n\n创建一个回调，当执行时将向组件发送一批消息。与 `callback` 的区别在于，传递给此方法的闭包不必返回消息。相反，闭包可以返回 `Vec<Msg>` 或 `Option<Msg>`，其中 `Msg` 是组件的消息类型。\n\n`Vec<Msg>` 被视为一批消息，并在内部使用 `send_message_batch`。\n\n`Option<Msg>` 在值为 `Some` 时调用 `send_message`。如果值为 `None`，则不执行任何操作。这可以用于根据情况，不需要更新的情况。\n\n这是通过使用仅为这些类型实现的 `SendAsMessage` trait 实现的。您可以为自己的类型实现 `SendAsMessage`，这样可以在 `batch_callback` 中使用它们。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/agents.mdx",
    "content": "---\ntitle: '代理 (Agents)'\ndescription: \"Yew's 的代理系统\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n代理 (Agents) 是一种将任务卸载到 Web Workers 的方式。\n\n为了使代理能够并发运行，Yew 使用了 [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命周期\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## 代理的类型\n\n### 范围\n\n- 公开 - 在任何给定时间，公共代理的实例最多只有一个。桥梁将在 Web Worker 中生成或连接到已经生成的代理。当没有桥梁连接到此代理时，代理将消失。\n\n- 私有 - 为每个新的桥梁在 Web Worker 中生成一个新的代理。这对于将与浏览器通信的共享但独立的行为从组件中移出是很好的。当连接的桥梁被丢弃时，代理将消失。\n\n- 全局 \\(WIP\\)\n\n## 代理与组件之间的通信\n\n### 通信桥 (Bridges)\n\n通信桥 (bridge) 是一个组件和代理之间的通信通道。它允许组件向代理发送消息，并接收来自代理的消息。\n\n`use_bridge` 钩子也提供了在函数组件中创建桥梁的功能。\n\n### 派发器 (Dispatchers)\n\n派发器 (Dispatchers) 允许组件和代理之间进行单向通信，组件以此方式向代理发送消息。\n\n## 开销\n\n代理使用 Web Workers（即私有和公开）。它们在发送和接收消息时会产生序列化开销。代理使用 [bincode](https://github.com/bincode-org/bincode) 与其他线程通信，因此成本比仅调用函数要高得多。\n\n## 进一步阅读\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 示例展示了组件如何向代理发送消息并接收来自代理的消息。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: '使用 classes! 宏处理 CSS 类'\ndescription: '用一个方便的宏来处理 CSS 类'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew 并没有提供原生的 CSS-in-Rust 解决方案，但通过提供编程方式与 HTML `class` 属性交互的方式来辅助样式。\n\n## `classes!` 宏\n\n`classes!` 宏和相关的 `Classes` 结构简化了 HTML 类的使用：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n更多 CSS 相关的内容请参见[这个文档](../../more/css)。\n\n## 内联样式\n\n目前 Yew 并没有提供特殊的辅助工具来处理通过 `style` 属性指定的内联样式，但你可以像处理其他 HTML 属性一样处理它：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n更多 CSS 相关的内容请参见[这个文档](../../more/css)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: '使用 html! 宏处理 HTML'\ndescription: '这是 HTML，但不完全是！'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n你可以使用 `html!` 宏编写类似 HTML 的表达式。Yew 会在后台将其转换为表达 DOM 的 Rust 代码。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\n类似于格式化表达式，您可以通过使用花括号将周围上下文的值嵌入 HTML 中：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n使用 `html!` 有一个重要的规则 - 您只能返回一个包装节点。为了渲染多个元素的列表，`html!` 允许使用空标签（Fragments）。空标签是没有名称的标签，它们本身不会产生 HTML 元素。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// 错误：只允许一个根 HTML 元素\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修复：使用 HTML 空标签包裹\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n更多关于 Yew 和 HTML 的内容请参见[更多 HTML](concepts/html/introduction.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'Javascript 与 Rust'\ndescription: '在 Rust 中使用 JavaScript'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew 在一个地方集中了一个可重用的 UI 部分可能需要的所有内容 - rust 文件，同时也在必要时保持底层技术的可访问性。\n\n截至今天，WebAssembly 对于 DOM 交互还不完全支持。这意味着即使在 Yew 中，我们有时也依赖于调用 JavaScript。接下来是涉及的库的概述。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一个在 JavaScript 和 Rust 函数之间建立调用桥梁的库和工具。\n\n我们强烈建议您查看他们的[文档](https://wasm-bindgen.github.io/wasm-bindgen/)和我们的[快速指南](./wasm-bindgen.mdx)。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 为 Web API 提供了绑定，并允许我们以一种经过 Rust 处理和安全的方式编写 JavaScript 代码。\n\n示例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n再次强调，我们强烈建议您查看他们的[文档](https://wasm-bindgen.github.io/wasm-bindgen/)和我们的[快速指南](./web-sys.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一个在 JavaScript 和 Rust 函数之间建立调用桥梁的库和工具。它是由 [Rust 和 WebAssembly 工作组](https://rustwasm.github.io/) 使用 Rust 构建的。\n\nYew 使用 `wasm-bindgen` 通过一些 crate 与浏览器进行交互：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\n本节将从更抽象的层次上探讨这些 crate，以便更容易地理解和使用 Yew 中的 `wasm-bindgen` API。要了解有关 `wasm-bindgen` 及其相关 crate 的更深入指南，请查看 [`wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/)。\n\n有关上述 crate 的文档，请查看 [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html)。\n\n:::tip\n使用 `wasm-bindgen` doc.rs 搜索来查找已使用 `wasm-bindgen` 导入的浏览器 API 和 JavaScript 类型。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\n这个 crate 为上面的其他 crate 提供了许多构建块。在本节中，我们只会涵盖 `wasm-bindgen` crate 的两个主要领域，即宏和一些您会一遍又一遍看到的类型/特性。\n\n### `#[wasm_bindgen]` macro\n\n`#[wasm_bindgen]` 宏提供了 Rust 和 JavaScript 之间的接口，提供了一个在两者之间进行转换的系统。使用这个宏更为高级，除非您要使用外部 JavaScript 库，否则不应该使用它。`js-sys` 和 `web-sys` crate 为内置 JavaScript 类型和浏览器 API 提供了 `wasm-bindgen` 定义。\n\n让我们通过一个简单的示例来使用 `#[wasm-bindgen]` 宏来导入一些特定版本的 [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 函数。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// 首先让我们手动绑定 `console.log`，而不使用 `web_sys` 的帮助。\n// 在这里，我们手动编写 `#[wasm_bindgen]` 注解，我们程序的正确性取决于这些注解的正确性！\n#[wasm_bindgen]\nextern \"C\" {\n    // 在这里使用 `js_namespace` 来绑定 `console.log(..)` 而不是只有 `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` 是多态的，所以我们可以使用多个签名绑定它。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 多个参数也是可以的！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// 使用导入的函数！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_这个示例是基于 [1.2 使用 console.log 的 `wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) 改编的。_\n\n### 模拟继承\n\n在 JavaScript 类之间的继承是 JavaScript 语言的核心特性，DOM（文档对象模型）是围绕它设计的。当使用 `wasm-bindgen` 导入类型时，您还可以添加描述它们继承关系的属性。\n\n在 Rust 中，这种继承关系使用 [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) 和 [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) 特性来表示。这里举个例子可能会有所帮助；假设您有三种类型 `A`、`B` 和 `C`，其中 `C` 扩展了 `B`，而 `B` 又扩展了 `A`。\n\n在导入这些类型时，`#[wasm-bindgen]` 宏将按照以下方式实现 `Deref` 和 `AsRef` 特性：\n\n- `C` 可以 `Deref` 到 `B`\n- `B` 可以 `Deref` 到 `A`\n- `C` 可以被 `AsRef` 到 `B`\n- `C` 和 `B` 都可以被 `AsRef` 到 `A`\n\n这些实现允许您在 `C` 的实例上调用 `A` 的方法，并将 `C` 用作 `&B` 或 `&A`。\n\n需要注意的是，使用 `#[wasm-bindgen]` 导入的每种类型都有相同的根类型，您可以将其视为上面示例中的 `A`，这种类型是 [`JsValue`](#jsvalue)，下面有它的部分。\n\n_[`wasm-bindgen` 指引中的 extends 部分](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\n这是 JavaScript 拥有的对象的表示，这是 `wasm-bindgen` 的根捕获类型。任何来自 `wasm-bindgen` 的类型都是 `JsValue`，这是因为 JavaScript 没有强类型系统，因此接受变量 `x` 的任何函数都不定义其类型，因此 `x` 可以是有效的 JavaScript 值；因此 `JsValue`。如果您正在使用接受 `JsValue` 的导入函数或类型，那么任何导入的值在技术上都是有效的。\n\n`JsValue` 可以被函数接受，但该函数可能仍然只接受某些类型，这可能会导致 panic - 因此在使用原始 `wasm-bindgen` API 时，请检查导入的 JavaScript 的文档，以确定是否会在该值不是某种类型时引发异常（panic）。\n\n_[`JsValue` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)。_\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust 有一个强类型系统，而 JavaScript……没有😞。为了让 Rust 保持这些强类型但仍然方便，WebAssembly 工作组提出了一个非常巧妙的特性 `JsCast`。它的工作是帮助您从一个 JavaScript \"类型\" 转换到另一个 \"类型\"，这听起来很模糊，但它意味着如果您有一个类型，您知道它是另一个类型，那么您可以使用 `JsCast` 的函数从一个类型跳到另一个类型。当使用 `web-sys`、`wasm_bindgen`、`js-sys` 时，了解这个很好的特性 - 您会注意到许多类型将从这些 crate 中实现 `JsCast`。\n\n`JsCast` 提供了转换的检查和不检查方法 - 因此在运行时，如果您不确定某个对象是什么类型，您可以尝试将其转换，这将返回可能的失败类型，如 [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) 和 [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)。\n\n一个常见的例子是在 [`web-sys`](./web-sys.mdx) 中，当您尝试获取事件的目标时。您可能知道目标元素是什么，但 [`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API 总是会返回一个 [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)。\n您需要将其转换为元素类型，以便调用其方法。\n\n```rust\n// 需要先导入这个 Trait\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // 也许目标是一个选择元素？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 做点别的\n        return;\n    }\n\n    // 如果它能确定不是一个选择元素，那么我可以肯定它是一个输入元素！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) 方法是一个检查的转换，返回一个 `Option<&T>`，这意味着如果转换失败，则可以再次使用原始类型，因此返回 `None`。[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 方法将消耗 `self`，这是 Rust 中 `into` 方法的约定，返回的类型是 `Result<T, Self>`。如果转换失败，则原始的 `Self` 值将在 `Err` 中返回。您可以再试一次或对原始类型进行其他操作。\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 类型提供了一种将 Rust 闭包传递到 JavaScript 的方法，出于健全性原因，传递给 JavaScript 的闭包必须具有 `'static` 生命周期。\n\n这种类型是一个“句柄”，意味着每当它被丢弃时，它将使其引用的 JS 闭包无效。在 `Closure` 被丢弃后，对 JS 中闭包的任何使用都将引发异常。\n\n当您使用接受类型 [`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 的 `js-sys` 或 `web-sys` API 时，通常会使用 `Closure`。在 [Events](../html/events.mdx) 页面的 [Using `Closure` 部分](../html/events.mdx#using-closure-verbose) 中可以找到在 Yew 中使用 `Closure` 的示例。\n\n_[`Closure` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` crate 提供了 JavaScript 标准内置对象的绑定/导入，包括它们的方法和属性。\n\n这不包括任何 Web API，因为这是 [`web-sys`](./web-sys.mdx) 的作用！\n\n_[`js-sys` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` crate 提供了一个桥梁，用于将 JavaScript Promise 类型作为 Rust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 进行处理，并包含将 Rust Future 转换为 JavaScript Promise 的实用程序。当在 Rust（wasm）中处理异步或其他阻塞工作时，这可能很有用，并提供了与 JavaScript 事件和 JavaScript I/O 原语进行交互的能力。\n\n目前这个 crate 中有三个主要接口：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   一个使用 [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) 构造的类型，然后可以用作 `Future<Output=Result<JsValue, JsValue>>`。如果 `Promise` 被解析，这个 `Future` 将解析为 `Ok`，如果 `Promise` 被拒绝，则解析为 `Err`，分别包含 `Promise` 的解析或拒绝值。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   将 Rust `Future<Output=Result<JsValue, JsValue>>` 转换为 JavaScript `Promise`。未来的结果将转换为 JavaScript 中的已解析或已拒绝 `Promise`。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   在当前线程上生成一个 `Future<Output = ()>`。这是在 Rust 中运行 Future 的最佳方法，而不是将其发送到 JavaScript。\n\n_[`wasm-bindgen-futures` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` 将是 Yew 中 `wasm-bindgen-futures` crate 中最常用的部分，因为这有助于使用具有异步 API 的库。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // 控制台输出 \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew 还在某些 API 中添加了对 futures 的支持，最值得注意的是您可以创建一个接受 `async` 块的 `callback_future` - 这在内部使用了 `spawn_local`。\n\n_[`spawn_local` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys crate 为 Web API 提供绑定。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 为 Web API 提供绑定。这是从浏览器 WebIDL 生成的，这就是为什么有些名称如此之长，有些类型如此模糊的原因。\n\n## `web-sys` 中的特性 (features)\n\n`web-sys` crate 中启用了所有特性可能会给 Wasm 应用程序增加很多冗余。为了解决这个问题，大多数类型都是通过启用 features 进行控制的，这样你只需要包含你的应用程序所需的类型。Yew 启用了 `web-sys` 的几个特性，并在其公共 API 中公开了一些类型。你通常需要自行将 `web-sys` 添加为依赖项。\n\n## `web-sys` 中的继承\n\n在[模拟继承](./wasm-bindgen.mdx#simulating-inheritance)部分，你可以了解到 Rust 通常提供了一种模拟 JavaScript 中继承的方法。这在 `web-sys` 中非常重要，因为了解一个类型上有哪些方法意味着了解它的继承。\n\n这一部分将查看一个特定的元素，并使用 Rust 调用 [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) 列出其继承，直到该值为 [`JsValue`](./wasm-bindgen.mdx#jsvalue)。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement 是 HTML 中的 <textarea>。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意我们现在已经从 web-sys 类型转移到内置的 JavaScript 类型，\n    // 这些类型在 js-sys crate 中。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意我们现在已经从 js-sys 类型转移到 wasm-bindgen crate 中的根 JsValue。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // 这样使用 deref 意味着我们必须手动遍历继承树。\n    // 但是，您可以在 HtmlTextAreaElement 类型上调用 JsValue 方法。\n    assert!(!text_area.is_string());\n\n    // 这个空函数只是为了证明我们可以将 HtmlTextAreaElement 作为 &EventTarget 传递。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // 编译器将沿着 deref 链向下走，以匹配这里的类型。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 实现允许您将 HtmlTextAreaElement 视为 &EventTarget。\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[`wasm-bindgen` 指引中的 `web-sys` 继承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)_\n\n## `NodeRef` 中的 `Node`\n\nYew 使用 [`NodeRef`](concepts/function-components/node-refs.mdx) 来提供一种方式来保留由 [`html!`](concepts/html/introduction.mdx) 宏创建的 `Node` 的引用。`NodeRef` 中的 `Node` 指的是 [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html)。`NodeRef::get` 方法将返回一个 `Option<Node>` 值，但是，在 Yew 中，大多数情况下，您希望将此值转换为特定元素，以便使用其特定方法。如果存在，可以使用 [`JsCast`](./wasm-bindgen.mdx#JsCast) 对 `Node` 值进行转换，但是 Yew 提供了 `NodeRef::cast` 方法来执行此转换，以方便使用，因此您不一定需要为 `JsCast` 特性包含 `wasm-bindgen` 依赖项。\n\n下面的两个代码块本质上是相同的，第一个使用 `NodeRef::cast`，第二个使用 [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 在 `NodeRef::get` 返回的 `web_sys::Node` 上。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // 在这里处理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // 在这里处理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript 重构为 Rust 的示例\n\n这一节展示了如何将与 Web API 交互的 JavaScript 代码示例重写为 Rust 中的 `web-sys`。\n\n### JavaScript 示例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e 为鼠标事件对象\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 元素内的 x 位置。\n    var y = e.clientY - rect.top // 元素内的 y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### 用 `web-sys` 重写的示例\n\n仅使用 `web-sys`，上面的 JavaScript 示例可以这样实现：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 需要启用所有我们想要使用的 web-sys 特性！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 我们现在需要保存 `mousemove` 闭包，以便在事件触发时闭包仍然在内存中。\n```\n\n这个版本更加冗长，但你可能会注意到其中的一部分是由于失败类型提醒我们，一些函数调用有必须保持的不变量，否则将在 Rust 中引发 panic。另一个冗长的部分是调用 `JsCast` 来将不同类型转换为特定类型，以便调用其特定方法。\n\n### 用 Yew 重写的示例\n\n在 Yew 中，您将主要创建 [`Callback`](concepts/function-components/callbacks.mdx) 以在 [`html!`](concepts/html/introduction.mdx) 宏中使用，因此示例将使用这种方法，而不是完全复制上面的方法：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# 我们需要启用 `DomRect` 特性以使用 `get_bounding_client_rect` 方法。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 补充依赖库\n\n`web-sys` 是 Web API 的原始绑定，因此在 Rust 中会有一些痛苦，因为它并不是为 Rust 或甚至强类型系统设计的，这就是社区 crate 提供了对 `web-sys` 的抽象，以提供更符合 Rust 习惯的 API。\n\n_[补充依赖库清单](/community/external-libs)_\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/contexts.mdx",
    "content": "---\ntitle: '上下文 (Contexts)'\nsidebar_label: Contexts\ndescription: '使用上下文传递深度嵌套数据'\n---\n\n通常，数据是通过 props 从父组件传递到子组件。\n但是，如果必须通过中间的许多组件传递它们，或者如果应用程序中的许多组件需要相同的信息，传递 props 可能会变得冗长和烦人。\n上下文解决了这个问题，允许父组件使数据可用于其下方树中的任何组件，无论多深，而无需通过 props 传递它们。\n\n## 使用 props 的问题：\"Prop Drilling\"\n\n传递 [props](./function-components/properties.mdx) 是从父组件直接传递数据到子组件的好方法。\n但是，当需要通过深层嵌套的组件树传递数据或多个组件共享相同的数据时，传递 props 变得繁琐。\n一种常见的数据共享解决方案是将数据提升到一个共同的祖先，并使子组件将其作为 props 接收。\n然而，这可能导致 props 必须通过多个组件才能到达需要它的组件。\n这种情况称为 \"Prop Drilling\"。\n\n考虑以下示例，它通过 props 传递主题：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App 根节点\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n我们通过 `Navbar` 传递主题设定，以便它可以到达 `Title` 和 `NavButton`。\n如果 `Title` 和 `NavButton` 这些需要访问主题的组件可以直接访问主题而不必通过 prop 传递，那就更好了。\n上下文解决了这个问题，允许父组件将数据（在这种情况下是主题）传递给其子组件。\n\n## 使用上下文\n\n### 步骤 1：提供上下文\n\n需要一个上下文提供者来消费上下文。`ContextProvider<T>`，其中 `T` 是用作提供者的上下文结构体。\n`T` 必须实现 `Clone` 和 `PartialEq`。`ContextProvider` 是其子组件将拥有上下文的组件。\n当上下文更改时，子组件会重新渲染。一个结构体用于定义要传递的数据。`ContextProvider` 可以这样使用：\n\n```rust\nuse yew::prelude::*;\n\n/// App 主题\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// 主组件\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` 是 `Rc<UseStateHandle<Theme>>` 类型，而我们需要 `Theme`\n        // 所以我们对它进行解引用。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // 这里的每个子组件及其子组件都将访问此上下文。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// 工具栏\n/// 此组件可以访问上下文。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// 放置在 `Toolbar` 中的按钮\n/// 由于此组件是组件树中 `ThemeContextProvider` 的子组件，它也可以访问上下文。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### 步骤 2：使用上下文\n\n#### 函数组件\n\n`use_context` 钩子用于在函数组件中使用上下文。\n请参阅 [use_context 文档](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) 了解更多信息。\n\n#### 结构体组件\n\n我们有两种选择在结构体组件中使用上下文：\n\n- [高阶组件](../advanced-topics/struct-components/hoc)：一个高阶函数组件将使用上下文并将数据传递给需要它的结构体组件。\n- 直接在结构体组件中使用上下文。请参阅 [结构体组件作为消费者的示例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## 使用场景\n\n通常，如果某些数据需要在树的不同部分的远程组件中使用，上下文可能会对你有所帮助。\n以下是一些这样的例子：\n\n- **主题**：你可以在应用程序的顶部放置一个上下文来保存你的应用程序主题，并使用它来调整视觉外观，如上例所示。\n- **当前用户帐户**：在许多情况下，组件需要知道当前登录的用户。你可以使用上下文将当前用户对象提供给组件。\n\n### 使用上下文前的考虑\n\n上下文非常容易使用，这也使得它们非常容易被误用/过度使用。\n仅仅因为你可以使用上下文将 props 共享给多个层级深的组件，并不意味着你应该这样做。\n\n例如，你可以提取一个组件并将该组件作为子组件传递给另一个组件。例如，\n你可能有一个 `Layout` 组件，它将 `articles` 作为 prop 并传递给 `ArticleList` 组件。\n你应该重构 `Layout` 组件，使其接受子组件作为 props 并显示 `<Layout> <ArticleList {articles} /> </Layout>`。\n\n## 修改子组件的上下文值\n\n由于 Rust 的所有权规则，上下文不能有一个可以被子组件调用的 `&mut self` 方法。\n要修改上下文的值，我们必须将其与 reducer 结合使用。这可以通过使用\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) 钩子来完成。\n\n[上下文示例](https://github.com/yewstack/yew/tree/master/examples/contexts) 演示了使用上下文的可变上下文\n\n## 进一步阅读\n\n- [上下文示例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: '回调 (Callbacks)'\n---\n\n回调函数用于在组件树中向上传递信息，以及在事件处理期间与其他组件（如代理或 DOM）进行通信。在内部，回调函数的类型只是一个 `Fn`，并且被包装在 `Rc` 中，以便它们可以被廉价地克隆。\n\n如果您想手动调用回调函数，可以使用 `emit` 函数。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // 调用回调函数\n// web_sys::console::log_1(&result.into()); // 如果取消注释，将打印 \"Bye Bob\"\n```\n\n## 将回调函数作为属性传递\n\n在 yew 中的一个常见模式是创建一个回调函数，并将其作为属性传递给子组件。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 然后提供属性 (Props)\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // 如果取消注释，这里会打印文本\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM 事件和回调函数\n\n回调函数也用于连接到 DOM 事件。\n\n例如，这里我们定义了一个回调函数，当用户点击按钮时将会调用：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // 如果取消注释，这里会打印文本\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子元素 (Children)'\n---\n\n`Children` 是一种特殊的属性类型，允许您接收嵌套的 `Html`，就像 html 子元素一样提供。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` 键很重要！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // 可以靠这种方式转发子元素\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/communication.mdx",
    "content": "---\ntitle: '组件之间的通信'\n---\n\n## 父组件向子组件发送消息\n\n将数据作为 [props](./properties) 传递，这会导致重新渲染，这是向子组件传递消息的方法。\n\n## 子组件向父组件发送消息\n\n通过 props 传递一个回调，子组件在事件上可以调用。[示例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/generics.mdx",
    "content": "---\ntitle: '泛型组件'\ndescription: '函数组件的 #[component] 属性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 属性也适用于用于创建泛型组件的泛型函数。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// 之后可以像这样使用\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// 或者\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: '自定义 Hooks'\n---\n\n## 定义自定义 Hooks\n\n组件的有状态逻辑可以通过创建自定义 Hooks 来提取为可重用的函数。\n\n假设我们希望创建一个事件监听器，监听 `window` 对象上的事件。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\n这段代码有一个问题：逻辑无法被另一个组件重用。如果我们构建另一个监听不同事件的组件，而不是复制代码，我们可以将逻辑移入自定义 hook。\n\n我们将首先创建一个名为 `use_event` 的新函数。`use_` 前缀表示函数是一个 hook。此函数将接受一个事件目标、一个事件类型和一个回调。所有 hook 必须在其函数定义上标记为 `#[hook]`。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\n这个简单的 hook 可以通过组合内置 hook 创建。在本例中，我们将使用 `use_effect_with` hook，因此当 hook 参数发生变化时，可以重新创建事件监听器。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\n尽管这种方法在几乎所有情况下都有效，但它无法用于编写像我们已经使用的预定义 hook 那样的基本 hook。\n\n查看 [docs.rs](https://docs.rs/yew) 上的文档以及 `hooks` 目录，查看预定义 hook 的实现。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks 是一类能够存储状态和执行副作用的函数。\n\nYew 提供了一些预定义的 hooks。您也可以创建自己的 hooks，或者发现许多[社区制作的 hooks](/community/awesome#hooks)。\n\n## Hooks 规则\n\n1. 每个 Hook 函数的名称必须以 `use_` 开头\n2. Hooks 只能在以下位置使用：\n    - 函数/ Hook 的顶层\n    - 函数/ Hook 内的块，只要它没有被分支\n    - 函数/ Hook 内顶层 `if` 表达式的条件\n    - 函数/ Hook 内顶层 `match` 表达式的选择器\n3. 每次渲染时，Hooks 必须以相同的顺序调用。只有在使用 [Suspense](../../suspense.mdx) 时才允许提前返回\n\n这些规则由编译时或运行时错误来执行。\n\n### 预定义 Hooks\n\nYew 提供了以下预定义 Hooks：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\n这些 hooks 的文档可以在 [Yew API 文档](https://yew-rs-api.web.app/next/yew/functional/)中找到。\n\n### 自定义 Hooks\n\n有些情况下，您可能希望定义自己的 Hooks，以将组件中的可能具有状态的逻辑封装到可重用的函数中。\n\n## 进一步阅读\n\n- React 文档中有一个关于 [React hooks](https://reactjs.org/docs/hooks-intro.html) 的部分。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函数组件'\nslug: /concepts/function-components\n---\n\n让我们重新回顾一下之前的标语：\n\n> Yew 的核心思想是将可重用的 UI 部分所需的所有内容集中在一个地方 - Rust 文件中。\n\n我们将通过引入将定义应用程序的逻辑和呈现行为的概念来完善这个陈述：\"组件\"。\n\n## 什么是组件？\n\n组件是 Yew 的构建块。\n\n它们应当：\n\n- 以 [Props](./properties.mdx) 的形式接受参数\n- 可以拥有自己的状态\n- 计算用户可见的 HTML 片段（DOM）\n\n## Yew 组件的两种风味\n\n您当前正在阅读有关函数组件的内容 - 这是在开始使用 Yew 时以及在编写简单的呈现逻辑时编写组件的推荐方式。\n\n还有一种更高级但不太容易访问的编写组件的方式 - [结构组件](advanced-topics/struct-components/introduction.mdx)。它们允许非常详细的控制，尽管大多数情况下您不需要那么详细的控制。\n\n## 创建函数组件\n\n要创建一个函数组件，请将 `#[component]` 属性添加到一个函数中。按照惯例，函数的名称采用 PascalCase，与 `html!` 宏中的普通 html 元素形成对比。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 然后在其他地方，您可以在 `html!` 中使用组件\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## 组件内部发生了什么\n\n在渲染时，Yew 将构建这些组件的虚拟树。它将调用每个（函数）组件的 view 函数来计算 DOM 的虚拟版本（VDOM），您作为库用户将其视为 `Html` 类型。对于上面的示例，这将如下所示：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n当需要更新时，Yew 将再次调用 view 函数，并将新的虚拟 DOM 与其之前的版本进行协调，并仅将新的/更改的/必要的部分传 播到实际的 DOM。这就是我们所说的 **渲染**。\n\n:::note\n\n实际上，`Html` 只是 `VNode` 的别名 - 一个虚拟节点。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: '节点引用'\ndescription: 'DOM 外部访问'\n---\n\n`ref` 属性可以用于将 `NodeRef` 附加到 HTML 元素上。在回调中，您可以获取 `ref` 附加到的 DOM `Element`。这可以用于在 `view` 生命周期方法之外对 DOM 进行更改，检索 `<input>` 的值以及通过 javascript API 直接与 DOM 交互。\n\n这对于获取 canvas 元素或滚动到页面的不同部分很有用。\n\n:::caution\n不要手动修改 Yew 渲染的 DOM 树。如果不确定，请将 `NodeRef` 视为只读访问。\n:::\n\n## 进一步阅读\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` 示例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '属性 (Properties)'\ndescription: '父子组件通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n属性 (Properties) 通常被简写为 \"Props\"。\n\n:::\n\n属性 (Properties) 是组件的参数，Yew 可以监视这些参数。\n\n在组件的属性中使用一个类型之前，它必须实现 `Properties` trait。\n\n## 响应性\n\n在重新渲染时，Yew 在协调虚拟 DOM 时检查属性是否已更改，以了解是否需要重新渲染嵌套组件。这样，Yew 可以被认为是一个非常具有响应性的框架，因为来自父组件的更改总是会向下传播，视图永远不会与来自属性/状态的数据不同步。\n\n:::tip\n\n如果您尚未完成 [教程](../../tutorial)，请尝试并自行测试这种响应性！\n\n:::\n\n## 派生宏\n\nYew 提供了一个派生宏，可以轻松地在结构体上实现 `Properties` trait。\n\n您派生 `Properties` 的类型也必须实现 `PartialEq`，以便 Yew 可以进行数据比较。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函数组件中使用\n\n属性 `#[component]` 允许在函数参数中选择性地接收 Props。要提供它们，可以通过 `html!` 宏中的属性进行赋值。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// 然后提供属性\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 没有属性需要提供\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生宏字段属性\n\n在派生 `Properties` 时，默认情况下所有字段都是必需的。\n\n以下属性允许您为属性提供默认值，当父组件没有设置它们时将使用这些默认值。\n\n:::tip\n属性在 Rustdoc 生成的文档中是不可见的。您的属性的文档字符串应该提到一个属性是否是可选的，以及它是否有一个特殊的默认值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` trait 的字段类型的默认值初始化属性值。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 这样使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 来初始化属性值。`value` 可以是返回字段类型的任何表达式。\n\n例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。当属性被构造时，表达式会被评估，且没有给出明确的值。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// 这样使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n调用 `function` 来初始化属性值。`function` 应该具有 `FnMut() -> T` 签名，其中 `T` 是字段类型。当没有为该属性给出明确的值时，将调用该函数。\n这个函数在属性被构造时被调用。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// 使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的性能开销\n\n内部属性是以引用计数的智能指针传递的。这意味着只有一个共享指针被传递到组件树中的属性，这样就能节约克隆整个属性的高昂成本。\n\n:::tip\n`AttrValue` 是我们用于属性值的自定义类型，这样就不用将它们定义为 String 或其他类似克隆成本高昂的类型了。\n:::\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n该宏使用与结构表达式相同的语法，只是您不能使用属性或基本表达式 (`Foo { ..base }`)。类型路径可以直接指向属性 (`path::to::Props`)，也可以指向组件的关联属性 (`MyComp::Properties`)。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 注意我们不需要指定 name 属性\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自动生成属性 (yew-autoprops)\n\n为了简化您的开发流程，您还可以使用宏 `#[autoprops]`（来自 `yew-autoprops` 包）自动生成 `Properties` 结构体。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] 宏必须出现在 #[component] 之前，顺序很重要\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 结构体 \"GreetingsProps\" 将会被自动生成。\n//\n// `is_loading` 将作为值传递给组件，而 `message` 和 `name` 将使用引用，因为定义中有一个前导的 `&`。\n```\n\n## 评估顺序\n\n属性按照指定的顺序进行评估，如下例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n虽然几乎任何 Rust 类型都可以作为属性传递，但有一些反模式应该避免。这些包括但不限于：\n\n1. 使用 `String` 类型而不是 `AttrValue`。 <br />\n   **为什么不好？** `String` 克隆成本高昂。当属性值与钩子和回调一起使用时，通常需要克隆。`AttrValue` 是一个引用计数的字符串 (`Rc<str>`) 或一个 `&'static str`，因此非常便宜克隆。<br />\n   **注意**：`AttrValue` 在内部是来自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看该包以了解更多信息。\n2. 使用内部可变性。 <br />\n   **为什么不好？** 内部可变性（例如 `RefCell`、`Mutex` 等）应该 _通常_ 避免使用。它可能会导致重新渲染问题（Yew 不知道状态何时发生了变化），因此您可能需要手动强制重新渲染。就像所有事物一样，它有其用武之地。请谨慎使用。\n3. 使用 `Vec<T>` 类型而不是 `IArray<T>`。 <br />\n   **为什么不好？** `Vec<T>`，就像 `String` 一样，克隆成本也很高。`IArray<T>` 是一个引用计数的切片 (`Rc<[T]>`) 或一个 `&'static [T]`，因此非常便宜克隆。<br />\n   **注意**：`IArray` 可以从 [implicit-clone](https://crates.io/crates/implicit-clone) 导入。查看该包以了解更多信息。\n4. 您发觉可能的新内容。您是否遇到了一个希望早点了解清楚的边缘情况？请随时创建一个问题或向本文档提供修复的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一个实验性包，允许您根据函数的参数动态创建 Props 结构体。如果属性结构体永远不会被重用，这可能会很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '纯组件'\n---\n\n每个函数组件都是一个[纯](https://zh.wikipedia.org/wiki/%E7%BA%AF%E5%87%BD%E6%95%B0)函数，它接受一个属性对象并返回一个 `Html` 对象。纯函数是指在给定相同输入时，总是返回相同输出的函数。\n\n这个例子是一个纯组件。对于给定的属性 `is_loading`，它总是返回相同的 `Html`，没有任何副作用。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n如果您有一个内部纯组件，它不使用 hooks 和其他组件机制，您通常可以将其编写为返回 `Html` 的普通函数，从而避免 Yew 运行组件生命周期相关的一些开销。使用 [表达式语法](concepts/html/literals-and-expressions.mdx#expressions) 在 `html!` 中渲染它们。\n:::\n\n## 非纯组件\n\n您可能想知道，如果组件不使用任何全局变量，那么它是否可以是不“纯”的，因为它只是在每次渲染时调用的固定函数。\n这就是下一个主题 - [hooks](./hooks) 的用武之地。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/state.mdx",
    "content": "---\ntitle: '状态'\n---\n\n## 如何存储状态的一般视图\n\n这个表格可以作为一个指南，帮助您决定哪种状态存储类型最适合您的用例：\n\n| Hook             | 类型                       | 何时渲染?                        | 作用域                   |\n| ---------------- | -------------------------- | -------------------------------- | ------------------------ |\n| [use_state]      | `T`                        | 被设置一个值                     | 组件内部实例             |\n| [use_state_eq]   | `T: PartialEq`             | 被设置一个不同的值               | 组件内部实例             |\n| [use_reducer]    | `T: Reducible`             | 被调用归纳                       | 组件内部实例             |\n| [use_reducer_eq] | `T: Reducible + PartialEq` | 被调用归纳，归纳后的值与之前不同 | 组件内部实例             |\n| [use_memo]       | `Deps -> T`                | 依赖项发生变化                   | 组件内部实例             |\n| [use_callback]   | `Deps -> Callback<E>`      | 依赖项发生变化                   | 组件内部实例             |\n| [use_mut_ref]    | `T`                        | -                                | 组件内部实例             |\n| 全局静态常量     | `T`                        | -                                | 全局，任何位置都可以使用 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/classes.mdx",
    "content": "---\ntitle: '类'\ndescription: '一个方便的宏来处理类'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 类\n\n`Classes` 结构体可以用来处理 HTML 类。\n\n将字符串推送到集合时，`Classes` 确保每个类都有一个元素，即使单个字符串可能包含多个类。\n\n`Classes` 也可以通过使用 `Extend`（即 `classes1.extend(classes2)`）或 `push()`（即 `classes1.push(classes2)`）来合并。任何实现 `Into<Classes>` 的类型都可以推送到现有的 `Classes` 上。\n\n`classes!` 是一个方便的宏，它创建一个单一的 `Classes`。它的输入接受一个逗号分隔的表达式列表。唯一的要求是每个表达式都实现了 `Into<Classes>`。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 接受类的组件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/components.mdx",
    "content": "---\ntitle: '组件'\ndescription: '使用组件层次结构创建复杂的布局'\n---\n\n## 基础\n\n组件可以在 `html!` 宏中使用：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // 没有属性\n        <MyComponent />\n\n        // 使用属性\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // 一次性提供所有属性\n        <MyComponentWithProps ..props.clone() />\n\n        // 使用变量中的属性，并覆盖特定值\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## 嵌套\n\n如果组件在其 `Properties` 中有一个 `children` 字段，它可以接受子组件/元素\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` 宏允许您使用 `..props` 语法传递一个基本表达式，而不是单独指定每个属性，类似于 Rust 的[函数式更新语法](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax)。\n这个基本表达式必须出现在传递任何单独的 props 之后。\n当传递一个带有 `children` 字段的基本 props 表达式时，`html!` 宏中传递的子元素将覆盖已经存在于 props 中的子元素。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子元素将覆盖 props.children\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 相关示例\n\n- [函数化 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [函数化路由](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '条件渲染'\ndescription: '在 html 中有条件地渲染节点！'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If 块\n\n要有条件地渲染一些标记，我们将其包装在 `if` 块中：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/elements.mdx",
    "content": "---\ntitle: '元素'\ndescription: '支持 HTML 和 SVG 元素'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM 节点\n\n在 Yew 中手动创建或管理 DOM 节点的原因有很多，比如与可能与受管理组件冲突的 JS 库集成。\n\n使用 `web-sys`，您可以创建 DOM 元素并将其转换为 `Node` - 然后可以使用 `VRef` 将其用作 `Html` 值：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // 带记忆能力的函数，只会执行一次\n    let node = use_memo(\n        (),\n        |_| {\n            // 从文档中创建一个 div 元素\n            let div: Element = document().create_element(\"div\").unwrap();\n            // 添加内容、类等\n            div.set_inner_html(\"Hello, World!\");\n            // 将 Element 转换为 Node\n            let node: Node = div.into();\n            // 将该 Node 作为 Html 值返回\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo 返回的是 Rc 指针，所以我们需要解引用和克隆\n    (*node).clone()\n}\n\n```\n\n## 动态标签名\n\n在构建高阶组件时，您可能会发现自己处于一个标签名不是静态的情况。例如，您可能有一个 `Title` 组件，根据级别属性可以渲染从 `h1` 到 `h6` 的任何内容。而不是使用一个大的匹配表达式，Yew 允许您动态设置标签名，使用 `@{name}`，其中 `name` 可以是返回字符串的任何表达式。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 逻辑值属性\n\n一些内容属性（例如 checked、hidden、required）被称为逻辑值属性。在 Yew 中，逻辑值属性需要设置为布尔值：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\n这与以下的 **HTML** 功能上是等价的：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n将逻辑值属性设置为 false 等效于不使用该属性；可以使用逻辑表达式的值：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\n这与以下 **HTML** 结果等价：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 类似字符串的属性\n\n除了一些逻辑值属性，您可能会处理很多类似字符串的 HTML 属性，Yew 有几种选项可以将类似字符串的值传递给组件。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\n它们都是有效的，**但**我们鼓励您更倾向于使用 Yew 的自定义 `AttrValue`，特别是如果您需要克隆或将它们作为属性传递给另一个组件。\n\n## HTML 元素的可选属性\n\n大多数 HTML 属性可以使用可选值（Some(x) 或 None）。这使我们可以在属性被标记为可选时省略该属性。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n如果属性设置为 `None`，则该属性将不会在 DOM 中设置。\n\n## 相关示例\n\n- [内嵌 HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/events.mdx",
    "content": "---\ntitle: '事件'\n---\n\n## 介绍\n\nYew 与 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate 集成，并使用该 crate 中的事件。下面的[表格](#event-types)列出了在 `html!` 宏中接受的所有 `web-sys` 事件。\n\n您仍然可以为下表中未列出的事件添加 [`Callback`](../function-components/callbacks.mdx)，请参见[手动事件监听器](#manual-event-listener)。\n\n## 事件类型\n\n:::tip\n所有的事件类型都在 `yew::events` 下重新导出。\n使用 `yew::events` 中的类型比手动将 `web-sys` 作为依赖项包含在您的 crate 中更容易确保版本兼容性，\n因为您不会使用与 Yew 指定的版本冲突的版本。\n:::\n\n事件监听器的名称是在 `html` 宏中添加事件 `Callback` 时预期的名称：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\n事件名称是监听器名称去掉 \"on\" 前缀，因此 `onclick` 事件监听器监听 `click` 事件。查看本页末尾的[完整事件列表](#available-events)及其类型。\n\n## 事件捕获 {#event-bubbling}\n\nYew 调度的事件遵循虚拟 DOM 层次结构，向上冒泡到监听器。目前，仅支持监听器的冒泡阶段。请注意，虚拟 DOM 层次结构通常（但并非总是）与实际 DOM 层次结构相同。在处理[传送门](../../advanced-topics/portals)和其他更高级技术时，这一区别很重要。对于良好实现的组件，直觉应该是事件从子组件冒泡到父组件。这样，您在 `html!` 中编写的层次结构就是事件处理程序观察到的层次结构。\n\n如果您不想要事件冒泡，可以通过调用\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n在启动应用程序*之前*。这会加快事件处理速度，但某些组件可能会因未收到预期的事件而中断。请谨慎使用！\n\n## 事件委托\n\n可能会让人惊讶的是，事件监听器并不是直接注册在它们被渲染的元素上。相反，事件是从 Yew 应用的子树根节点委托的。不过，事件仍然以其原生形式传递，并且不会创建任何合成形式。这可能会导致 HTML 监听器中预期的事件与 Yew 中出现的事件之间的不匹配。\n\n- [`Event::current_target`] 指向 Yew 子树根节点，而不是添加监听器的元素。如果您想访问底层的 `HtmlElement`，请使用 [`NodeRef`](../function-components/node-refs.mdx)。\n- [`Event::event_phase`] 始终是 [`Event::CAPTURING_PHASE`]。在内部，事件将表现得像是在冒泡阶段，事件传播将被重放，并且事件会[向上冒泡](#event-bubbling)，即虚拟 DOM 中较高的事件监听器将在较低的事件监听器之后触发。目前，Yew 不支持捕获监听器。\n\n这也意味着由 Yew 注册的事件通常会在其他事件监听器之前触发。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 具备类型的事件目标\n\n:::caution\n在本节中，**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** 始终指的是事件从其派发的元素。\n\n这**不一定**总是指代 `Callback` 所放置的元素。\n:::\n\n在事件 `Callback` 中，您可能希望获取该事件的目标。例如，`change` 事件没有提供任何信息，但用于通知某些内容已更改。\n\n在 Yew 中，以正确的类型获取目标元素可以通过几种方式完成，我们将在这里逐一介绍。调用事件上的 [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) 返回一个可选的 [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 类型，当您想知道输入元素的值时，这可能看起来不是很有用。\n\n在下面的所有方法中，我们将解决相同的问题，以便清楚地了解方法的不同之处，而不是手头的问题。\n\n**问题：**\n\n我们在 `<input>` 元素上有一个 `onchange` `Callback`，每次调用时，我们希望向组件发送一个[更新](components#update) `Msg`。\n\n我们的 `Msg` 枚举如下所示：\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### 使用 `JsCast`\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate 有一个有用的 trait：[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)，它允许我们在类型之间直接转换，只要它实现了 `JsCast` 就行。我们可以谨慎地转换，这涉及运行时检查和处理 `Option` 和 `Result` 的逻辑，或者我们也可以冒险直接强行转换。\n\n多说无益，看代码：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# 需要 wasm-bindgen 用于调用 JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // 当事件被创建时，目标是未定义的，只有在派发时才会添加目标。\n            let target: Option<EventTarget> = e.target();\n            // 事件可能会冒泡，因此此侦听器可能会捕获不是 HtmlInputElement 类型的子元素的事件。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // 你必须了解 target 是 HtmlInputElement，否则调用 value 将是未定义行为（UB）。\n        // 在这里，我们确信这是输入元素，因此我们可以在不检查的情况下将其转换为适当的类型。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` 提供的方法是 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\n和 [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)。\n如你所见，它们允许我们从 `EventTarget` 转换为 [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html)。\n`dyn_into` 方法是谨慎的，因为它会在运行时检查类型是否实际为 `HtmlInputElement`，如果不是则返回\n`Err(JsValue)`。[`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n是一个通用类型，将原来的对象返回给你，以便再次尝试转换为别的类型。\n\n这会儿你可能会想，什么时候可以使用危险版本？在上面的情况下，它是安全的<sup>1</sup>，因为我们将 `Callback` 设置在一个没有子元素的元素上，所以目标只能是同一个元素。\n\n_<sup>1</sup> 只要涉及到 JS 领域，就是安全的。_\n\n### 使用 `TargetCast`\n\n**强烈建议先阅读 [使用 JsCast](#using-jscast)！**\n\n:::note\n`TargetCast` 的设计目的是让新用户了解 `JsCast` 的行为，但范围更小，仅涉及事件及其目标。\n\n选用 `TargetCast` 或 `JsCast` 纯粹是个人偏好，实际您会发现 `TargetCast` 的实现和 `JsCast` 的功能很相似。\n:::\n\n`TargetCast` trait 是在 `JsCast` 基础之上构建的，专门用于从事件中获取类型化的事件目标。\n\n`TargetCast` 是 Yew 的一部分，因此无需添加依赖项即可在事件上使用 trait 方法，但它的工作方式与 `JsCast` 非常相似。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // 你必须清楚 target 是 HtmlInputElement，否则调用 value 将是未定义行为（UB）。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n如果您已经了解了 `JsCast`，或者了解了这个 trait，您可能会发现 `TargetCast::target_dyn_into` 与 `JsCast::dyn_into` 相似，但专门用于事件的目标。`TargetCast::target_unchecked_into` 与 `JsCast::unchecked_into` 类似，因此上面关于 `JsCast` 的所有警告都适用于 `TargetCast`。\n\n### 使用 `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) 可以代替查询给定给 `Callback` 的事件。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n通过 `NodeRef`，你可以忽略事件并使用 `NodeRef::cast` 方法获取一个 `Option<HtmlInputElement>` - 这是可选的，因为在设置 `NodeRef` 之前调用 `cast`，或者类型不匹配时将返回 `None`。\n\n你可能会看到，通过使用 `NodeRef`，我们不必将 `String` 发送回状态，因为我们总是访问 `input_node_ref` - 因此我们可以这样做：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // 对 value 做点什么\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\n您选择哪种方法取决于您的组件和您的偏好，没有所谓的*推荐*方法。\n\n## 手动事件监听器\n\n您可能希望监听 Yew 的 `html` 宏不支持的事件，查看[这里列出的支持的事件](#event-types)。\n\n为了手动向某个元素添加事件监听器，我们需要借助 [`NodeRef`](../function-components/node-refs.mdx)，以便在 `use_effect_with` 中使用 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) 和 [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API 添加监听器。\n\n以下示例将展示如何为虚构的 `custard` 事件添加监听器。所有不受 yew 支持的事件或自定义事件都可以表示为\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html)。如果您需要访问自定义/不受支持事件的特定方法或字段，可以使用\n[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) 的方法将其转换为所需的类型。\n\n### 使用 `Closure`（冗长版本）\n\n直接使用 `web-sys` 和 `wasm-bindgen` 的接口可能有点痛苦……所以要有点心理准备（[感谢 `gloo`，有了更简洁的方法](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 创建您通常会创建的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 对 custard 做点什么..\n                    });\n\n                    // 从 Box<dyn Fn> 创建一个 Closure - 这必须是 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有关 `Closure` 的更多信息，请参见 [wasm-bindgen 指南](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html)。\n\n### 使用 `gloo`（简洁版本）\n\n更方便的方法是使用 `gloo`，更具体地说是 [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)，\n它是 `web-sys`、`wasm-bindgen` 的高层抽象实现。\n\n`gloo_events` 提供了 `EventListener` 类型，可以用于创建和存储事件监听器。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 创建您通常会创建的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 对 custard 做点什么..\n                    });\n\n                    // 从 Box<dyn Fn> 创建一个 Closure - 这必须是 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有关 `EventListener` 的更多信息，请参见 [gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html)。\n\n## 可用事件的完整列表 {#available-events}\n\n| 侦听器名称                  | `web_sys` 事件类型                                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空标签 (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 宏总是需要一个根节点。为了绕过这个限制，您可以使用一个“空标签”（也称为“fragments”）。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// 错误：只允许一个根 HTML 元素\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: '用于生成 HTML 和 SVG 的过程宏'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 宏允许您声明性地编写 HTML 和 SVG 代码。它类似于 JSX（一种允许您在 JavaScript 中编写类似 HTML 的代码的扩展）。\n\n**重要提示**\n\n1. `html! {}` 宏只能接受一个根 HTML 节点（您可以通过使用 [fragments](./fragments.mdx) 或 [iterators](./../html/lists.mdx) 来规避这一点）\n2. 空的 `html! {}` 调用是有效的，不会渲染任何内容\n3. 字面量必须始终用引号引起来并用大括号括起来：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` 宏会将所有标签名称转换为小写。要使用大写字符（某些 SVG 元素所需的字符）请使用[动态标签名称](concepts/html/elements.mdx#dynamic-tag-names)：`html! { <@{\"myTag\"}></@> }`\n\n:::note\n`html!` 宏可能会达到编译器的默认递归限制。如果遇到编译错误，请在 crate 根目录添加类似 `#![recursion_limit=\"1024\"]` 的属性以解决问题。\n:::\n\n## 标签 (Tags) 结构\n\n标签 (Tags) 基于 HTML 标签。组件、元素和列表都基于此标签语法。\n\n标签必须要么自闭合 `<... />`，要么对于每个开始标签都有一个相应的结束标签。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 缺少闭合标签\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 缺少闭合标签\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n方便起见，通常需要闭合标签的元素**允许**自闭合。例如，编写 `html! { <div class=\"placeholder\" /> }` 是有效的。\n:::\n\n创建复杂的嵌套 HTML 和 SVG 布局还是很容易的：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\n如果您使用 Rust 编译器的开发者版本编译 Yew，宏将警告您可能遇到的一些常见陷阱。当然，您可能需要使用稳定版编译器（例如，您的组织可能有政策要求这样做）进行发布构建，但即使您使用的是稳定工具链，运行 `cargo +nightly check` 也可能会标记一些可以改进 HTML 代码的方法。\n\n目前，这些 lint 主要与可访问性相关。如果您有 lint 的想法，请随时[在此问题中发表意见](https://github.com/yewstack/yew/issues/1334)。\n\n## 指定属性和属性\n\n属性与普通 HTML 中的元素设置方式相同：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n属性在元素名称之前用 `~` 指定：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n如果值是一个字面量的话，围绕值的大括号可以省略。\n\n:::\n\n:::note 什么是字面量\n\n字面量是 Rust 中所有有效的[字面量表达式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)。请注意，[负数**不是**字面量](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)，因此必须用大括号括起来 `{-6}`。\n\n:::\n\n:::note 组件属性\n组件属性作为 Rust 对象传递，与此处描述的元素参数 (Attributes) / 属性 (Properties) 不同。\n在[组件属性](../function-components/properties.mdx)中了解更多信息。\n:::\n\n### 特殊属性\n\n有一些特殊属性不直接影响 DOM，而是作为 Yew 虚拟 DOM 的指令。目前有两个这样的特殊属性：`ref` 和 `key`。\n\n`ref` 允许您直接访问和操作底层 DOM 节点。有关更多详细信息，请参阅[Refs](../function-components/node-refs.mdx)。\n\n另一方面，`key` 为元素提供了一个唯一标识符，Yew 可以用于优化目的。\n\n:::info\n[了解更多相关内容](./html/lists)\n:::\n\n## 条件渲染\n\n可以通过使用 Rust 的条件结构来条件性地渲染标记。目前只支持 `if` 和 `if let`。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n阅读[条件渲染](./conditional-rendering.mdx)一节了解更多\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/lists.mdx",
    "content": "---\ntitle: '列表'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 迭代器\n\n从迭代器构建 HTML 有 3 种方法：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` 循环\">\n主要方法是使用 for 循环，与 Rust 中已有的 for 循环相同，但有 2 个关键区别：\n1. 与标准 for 循环不能返回任何内容不同，`html!` 中的 for 循环会被转换为节点列表；\n2. 发散表达式，即 `break`、`continue` 在 `html!` 中的 for 循环体内是不允许的。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` 块\">\n另一种方法是使用 `for` 关键字，这不是原生的 Rust 语法，而是由 HTML 宏用于输出显示迭代器所需的代码。\n当迭代器已经计算好，只需要将其传递给宏时，这种方法比第一种更好。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` 方法\">\n\n最后一种方法是在迭代器的最终转换上调用 `collect::<Html>()`，它返回一个 Yew 可以显示的列表。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 键 (Key) 列表\n\n键 (Key) 列表是一个优化的列表，其中**所有**子元素都有键。\n`key` 是 Yew 提供的一个特殊属性，它为 HTML 元素或组件提供一个唯一标识符，用于 Yew 内部的优化。\n\n:::caution\nKey 只需要在每个列表中是唯一的，与 HTML `id` 的全局唯一性相反。它不应该依赖于列表的顺序。\n:::\n\n始终建议为列表添加键 (key)。\n\n可以通过将唯一的 `String`、`str` 或整数传递给特殊的 `key` 属性来添加键：\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### 性能优化\n\n我们有一个[带有键 (keys) 的列表示例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)可以让你测试性能上的改进，这里是一个简单的测试流程：\n\n1. 进入[在线演示](https://examples.yew.rs/keyed_list)\n2. 添加 500 个元素\n3. 禁用键\n4. 反转列表\n5. 查看 \"最后一次渲染花费了 Xms\"（在撰写本文时，大约为 60ms）\n6. 启用键\n7. 再次反转列表\n8. 查看 \"最后一次渲染花费了 Xms\"（在撰写本文时，大约为 30ms）\n\n截至撰写本文时，对于 500 个组件，速度提高了 2 倍。\n\n### 原理解释\n\n通常，当你迭代时，只需要在每个列表项上添加一个键，数据的顺序可能会发生变化。\n在重新渲染列表时，它用于加速协调过程。\n\n如果没有键，假设你迭代 `[\"bob\", \"sam\", \"rob\"]`，最终得到的 HTML 如下：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n然后在下一次渲染时，如果你的列表更改为 `[\"bob\", \"rob\"]`，Yew 可以删除 id=\"rob\" 的元素，并将 id=\"sam\" 更新为 id=\"rob\"。\n\n如果你为每个元素添加了一个键，初始 HTML 将保持不变，但在使用修改后的列表 `[\"bob\", \"rob\"]` 进行渲染后，Yew 只会删除第二个 HTML 元素，而其他元素则保持不变，因为它可以使用键将它们关联起来。\n\n如果你遇到了一个从一个组件切换到另一个组件的 bug/\"feature\"，但两者都有一个 div 作为最高渲染元素。\nYew 在这些情况下会重用已渲染的 HTML div 作为优化。\n如果你需要该 div 被重新创建而不是被重用，那么你可以添加不同的键，它们将不会被重用。\n\n## 进一步阅读\n\n- [TodoMVC 示例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [带有键 (keys) 的列表示例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [路由示例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: '字面量和表达式'\n---\n\n## 字面量\n\n如果表达式解析为实现了 `Display` 的类型，它们将被转换为字符串并插入到 DOM 中作为 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 节点。\n\n:::note\n字符串字面量创建 `Text` 节点，浏览器将其视为字符串。因此，即使表达式包含 `<script>` 标签，您也不会遇到 XSS 等安全问题，除非您将表达式包装在 `<script>` 块中。\n:::\n\n所有显示文本都必须用 `{}` 块括起来，因为文本被视为表达式。这是 Yew 与普通 HTML 语法最大的偏差。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 表达式\n\n您可以使用 `{}` 块在 HTML 中插入表达式，只要它们解析为 `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常将这些表达式提取到函数或闭包中以优化可读性是有意义的：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/router.mdx",
    "content": "---\ntitle: '路由 (Router)'\ndescription: 'Yew 的官方路由库'\n---\n\n单页应用程序 (SPA) 中的路由器处理根据 URL 显示不同的页面。与点击链接时请求不同的远程资源的默认行为不同，路由器会在本地设置 URL 以指向应用程序中的有效路由。然后，路由器检测到此更改并决定要渲染的内容。\n\nYew 在 `yew-router` crate 中提供了路由器支持。要开始使用它，请将依赖项添加到您的 `Cargo.toml` 文件中。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n所需的工具均在 `yew_router::prelude` 模块中提供，\n\n## 用法\n\n最开始，你需要定义一个 `Route`。\n\n路由由一个 `enum` 定义，它派生自 `Routable`。这个枚举必须实现 `Clone + PartialEq`。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` 与 `<Switch />` 组件配对，后者会找到与浏览器当前 URL 匹配的路径变体，并将其传递给 `render` 回调。然后回调决定要渲染的内容。如果没有路径匹配，路由器会导航到带有 `not_found` 属性的路径。如果没有指定路由，则不会渲染任何内容，并且会在控制台中记录一条消息，说明没有匹配的路由。\n\nyew-router 的大多数组件，特别是 `<Link />` 和 `<Switch />`，必须是某个 Router 组件（例如 `<BrowserRouter />`）的（深层）子元素。通常在应用程序中只需要一个 Router，通常由最顶层的 `<App />` 组件立即渲染。Router 注册了一个上下文，这是 Links 和 Switches 功能所需的。下面提供了一个示例。\n\n:::caution\n在浏览器环境中使用 `yew-router` 时，强烈推荐使用 `<BrowserRouter />`。您可以在 [API 参考](https://docs.rs/yew-router/) 中找到其他路由器类型。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### 路径段\n\n路由还可以使用动态和命名通配符段从路由中提取信息。然后，您可以在 `<Switch />` 内访问帖子的 id，并通过属性将其转发到相应的组件。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n您也可以使用普通的 `Post` 变体，而不是 `Post {id: String}`。例如，当 `Post` 与另一个路由器一起渲染时，该字段可能是多余的，因为另一个路由器可以匹配并处理路径。有关详细信息，请参阅下面的[嵌套路由器](#nested-router)部分。\n:::\n\n请注意，字段必须实现 `Clone + PartialEq` 作为 `Route` 枚举的一部分。它们还必须实现 `std::fmt::Display` 和 `std::str::FromStr` 以进行序列化和反序列化。整数、浮点数和字符串等原始类型已经满足这些要求。\n\n当路径的形式匹配，但反序列化失败（根据 `FromStr`）时。路由器将认为路由不匹配，并尝试渲染未找到的路由（或者如果未指定未找到的路由，则渲染空白页面）。\n\n参考以下示例：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// 切换函数会渲染 News 和 id。这里省略了。\n```\n\n当段超过 255 时，`u8::from_str()` 将失败并返回 `ParseIntError`，路由器将认为路由不匹配。\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\n有关路由语法和如何绑定参数的更多信息，请查看 [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params)。\n\n### 位置 (Location)\n\n路由器通过上下文提供了一个通用的 `Location` 结构，可以用于访问路由信息。它们可以通过钩子或 `ctx.link()` 上的便捷函数来检索。\n\n### 导航\n\n`yew_router` 提供了一些工具来处理导航。\n\n#### 链接\n\n`<Link />` 渲染为 `<a>` 元素，`onclick` 事件处理程序将调用 [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)，并将目标页面推送到历史记录中并渲染所需的页面，这正是单页应用程序所期望的行为。普通锚元素的默认 `onclick` 会重新加载页面。\n\n`<Link />` 组件还会将其子元素传递给 `<a>` 元素。可以将其视为应用内路由的 `<a/>` 替代品。不同之处在于你需要提供 `to` 属性而不是 `href`。示例用法如下：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n结构体变量也可以正常工作：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### 导航接口\n\n导航器 API 为函数组件和结构组件提供。它们使回调能够更改路由。可以在任一情况下获取 `Navigator` 实例以操作路由。\n\n##### 函数式组件\n\n对于函数组件，当底层导航器提供程序更改时，`use_navigator` 钩子会重新渲染组件。\n以下是实现一个按钮的示例，该按钮在点击时导航到 `Home` 路由。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\n这里的示例使用了 `Callback::from`。如果目标路由可以与组件所在的路由相同，或者只是为了安全起见，请使用普通的回调。例如，考虑在每个页面上都有一个徽标按钮，点击该按钮会返回主页。在主页上点击该按钮两次会导致代码崩溃，因为第二次点击会推送一个相同的 Home 路由，并且 `use_navigator` 钩子不会触发重新渲染。\n:::\n\n如果您想替换当前的位置而不是将新位置推到堆栈上，请使用 `navigator.replace()` 而不是 `navigator.push()`。\n\n您可能会注意到 `navigator` 必须移动到回调中，因此不能再次用于其他回调。幸运的是，`navigator` 实现了 `Clone`，例如，以下是如何为不同的路由设置多个按钮：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 结构体组件\n\n对于结构体组件，可以通过 `ctx.link().navigator()` API 获取 `Navigator` 实例。其余部分与函数组件的情况相同。以下是一个渲染单个按钮的视图函数示例。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### 重定向\n\n`yew-router` 还在 prelude 中提供了一个 `<Redirect />` 组件。它可以用于实现与导航器 API 类似的效果。该组件接受一个 `to` 属性作为目标路由。当渲染 `<Redirect/>` 时，用户将被重定向到属性中指定的路由。以下是一个示例：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // 建立对 `use_user` 的钩子\n    let user = match use_user() {\n        Some(user) => user,\n        // 当用户为 `None` 时重定向到登录页面\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 实际页面内容\n}\n```\n\n:::tip 如何选择 `Redirect` 或 `Navigator`\nNavigator API 是在回调中操作路由的唯一方法。\n而 `<Redirect />` 可以作为组件中的返回值使用。您可能还希望在其他非组件上下文中使用 `<Redirect />`，例如在[嵌套路由器](#nested-router)的 switch 函数中。\n:::\n\n### 监听变化\n\n#### 函数式组件\n\n您可以使用 `use_location` 和 `use_route` 钩子。当提供的值发生变化时，您的组件将重新渲染。\n\n#### 结构体组件\n\n为了响应路由变化，您可以将回调闭包传递给 `ctx.link()` 的 `add_location_listener()` 方法。\n\n:::note\n一旦位置监听器被删除，它将被取消注册。请确保将句柄存储在组件状态中。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // 处理事件\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` 和 `ctx.link().route::<R>()` 也可以用于一次性检索位置和路由。\n\n### 查询参数\n\n#### 在导航时指定查询参数\n\n为了在导航到新路由时指定查询参数，可以使用 `navigator.push_with_query` 或 `navigator.replace_with_query` 函数。它使用 `serde` 将参数序列化为 URL 的查询字符串，因此任何实现了 `Serialize` 的类型都可以传递。最简单的形式是包含字符串对的 `HashMap`。\n\n#### 获取当前路由的查询参数\n\n`location.query` 用于获取查询参数。它使用 `serde` 从 URL 的查询字符串中反序列化参数。\n\n## 嵌套路由器\n\n当应用程序变得更大时，嵌套路由器可能会很有用。考虑以下路由器结构：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\n嵌套的 `SettingsRouter` 处理所有以 `/settings` 开头的 URL。此外，它会将未匹配的 URL 重定向到主 `NotFound` 路由。因此，`/settings/gibberish` 将重定向到 `/404`。\n\n:::caution\n\n请注意，该接口仍在开发中，这样写的方式尚未最终确定\n\n:::\n\n可以使用以下代码实现：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### 基底路径 (Basename)\n\n可以使用 `yew-router` 定义基底路径 (Basename)。\n基底路径是所有路由的公共前缀。导航器 API 和 `<Switch />` 组件都支持基底路径设置。所有推送的路由都会加上基底路径前缀，所有的 switch 都会在尝试将路径解析为 `Routable` 之前去掉基底路径。\n\n如果没有为 Router 组件提供基底路径属性，它将使用 HTML 文件中 `<base />` 元素的 href 属性，并在 HTML 文件中没有 `<base />` 元素时回退到 `/`。\n\n## 相关示例\n\n- [路由](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## 接口参考\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/concepts/suspense.mdx",
    "content": "---\ntitle: '占位标签 (Suspense)'\ndescription: '用于数据获取的占位标签'\n---\n\n占位标签 (Suspense) 是一种在等待任务完成前暂停组件渲染的方式，同时显示一个回退（占位符）UI。\n\n它可以用于从服务器获取数据，等待代理完成任务，或执行其他后台异步任务。\n\n在占位标签出现之前，数据获取通常发生在组件渲染之后（渲染时获取）或之前（获取后渲染）。\n\n### 边渲染，边下载\n\n占位标签 (Suspense) 提供了一种新的方法，允许组件在渲染过程中发起数据请求。当组件发起数据请求时，渲染过程将被暂停，并显示一个回退 UI，直到请求完成。\n\n推荐使用钩子 (Hook) 来使用占位标签。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n在上面的示例中，`use_user` 钩子将在加载用户信息时暂停组件渲染，并在加载 `user` 之前显示 `Loading...` 占位符。\n\n要定义一个暂停组件渲染的钩子，它需要返回一个 `SuspensionResult<T>`。当组件需要被暂停时，钩子应该返回一个 `Err(Suspension)`，用户应该使用 `?` 解包它，这样它将被转换为 `Html`。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 当用户加载完成时，我们将其作为 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 当用户仍在加载时，我们创建一个 `Suspension`\n            // 并在数据加载完成时调用 `SuspensionHandle::resume`，\n            // 组件将自动重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### 关于实现暂停钩子 (Hook) 的注意事项\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) 返回 2 个值：暂停上下文本身和一个暂停句柄。后者负责在何时重新渲染暂停的组件，它提供了 2 种可互换的方法：\n\n1. 调用其 [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) 方法。\n2. 丢弃句柄。\n\n:::danger\n\n暂停句柄必须存储直到更新组件的时候，即使用新接收的数据；否则，暂停的组件将进入无限重新渲染循环，从而影响性能。\n在上面的示例中，暂停句柄通过移动到闭包中并传递给 `on_load_user_complete` 来保存。\n当虚拟用户加载时，将调用闭包，从而调用 `handle.resume()` 并重新渲染与暂停上下文相关的组件。\n\n:::\n\n# 完整示例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 如果用户已加载，则将其作为 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 当用户仍在加载时，我们创建一个 `Suspension`\n            // 并在数据加载完成时调用 `SuspensionHandle::resume`，\n            // 组件将自动重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 在结构体组件中使用占位标签\n\n直接暂停结构体组件是不可能的。然而，您可以使用一个函数组件作为[高阶组件](../advanced-topics/struct-components/hoc)来实现基于占位标签的数据获取。\n\nYew 仓库中的[占位标签示例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)演示了如何使用这个组件。\n\n## 相关示例\n\n- [占位标签](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: '构建一个示例应用'\n---\n\n当您的环境准备好后，您可以选择使用一个包含基本 Yew 应用所需样板的起始模板，或手动设置一个小项目。\n\n## 使用模板快速起步\n\n按照 [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) 的安装说明安装该工具，然后运行以下命令：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手动配置应用\n\n### 创建项目\n\n首先，请创建一个新的 cargo 项目。\n\n```bash\ncargo new yew-app\n```\n\n打开新创建的目录。\n\n```bash\ncd yew-app\n```\n\n### 运行一个 hello world 示例\n\n为了验证 Rust 环境是否设置正确，使用 `cargo run` 运行初始项目。您应该看到一个 \"Hello World!\" 消息。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### 将项目设置为 Yew web 应用\n\n为了将这个简单的命令行应用程序转换为一个基本的 Yew web 应用程序，需要进行一些更改。\n\n#### 更新 Cargo.toml\n\n将 `yew` 添加到依赖列表中。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在构建一个应用程序，你只需要 `csr` 特性。它将启用 `Renderer` 和所有与客户端渲染相关的代码。\n\n如果你正在制作一个库，请不要启用此特性，因为它会将客户端渲染逻辑拉入服务器端渲染包中。\n\n如果你需要 Renderer 进行测试或示例，你应该在 `dev-dependencies` 中启用它。\n\n:::\n\n#### 更新 main.rs\n\n我们需要生成一个模板，设置一个名为 `App` 的根组件，该组件渲染一个按钮，当点击时更新其值。用以下代码替换 `src/main.rs` 的内容。\n\n:::note\n`main` 函数中的 `yew::Renderer::<App>::new().render()` 调用启动您的应用程序并将其挂载到页面的 `<body>` 标签上。如果您想要使用任何动态属性启动您的应用程序，您可以使用 `yew::Renderer::<App>::with_props(..).render()`。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### 创建 index.html\n\n最后，在应用程序的根目录中添加一个 `index.html` 文件。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## 查看您的 Web 应用\n\n运行以下命令在本地构建和提供应用程序。\n\n```bash\ntrunk serve\n```\n\n:::info\n添加选项 '--open' 来打开您的默认浏览器 `trunk serve --open`。\n:::\n\nTrunk 将在您修改任何源代码文件时实时重新构建您的应用程序。\n默认情况下，服务器将在地址 '127.0.0.1' 的端口 '8080' 上监听 => [http://localhost:8080](http://127.0.0.1:8080)。\n要更改这部分配置，请创建以下文件并根据需要进行编辑：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 局域网上的监听地址\naddress = \"127.0.0.1\"\n# 广域网上的监听地址\n# address = \"0.0.0.0\"\n# 监听的端口\nport = 8000\n```\n\n## 恭喜\n\n您现在已经成功设置了您的 Yew 开发环境，并构建了您的第一个 Web 应用程序。\n\n尝试这个应用程序，并查看[示例](./examples.mdx)以进一步学习。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/getting-started/editor-setup.mdx",
    "content": "---\ntitle: '设置编辑器'\ndescription: '设置您的代码编辑器'\n---\n\n:::important 改进文档\n有在使用不同的编辑器？如有推荐，请随意添加您选择的编辑器的说明。\n:::\n\n## 为创建组件添加模板\n\n### JetBrains IDEs\n\n1. 从导航栏依次点击 File | Settings | Editor | Live Templates.\n2. 选择 Rust 并点击 + 图标添加新的 Live Template。\n3. 根据需要给它一个的名称和描述。\n4. 将以下代码片段粘贴到模板文本部分。\n5. 在右下角更改适用性，选择 Rust > Item > Module\n\n对于函数式组件，使用以下模板。\n\n- (可选) 点击编辑变量，并给 `tag` 一个合理的默认值，例如 \"div\"，用双引号。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n对于结构体组件，可以使用以下更复杂的模板。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. 从导航栏依次点击 File > Preferences > User Snippets.\n2. 选择 Rust 作为设置语言。\n3. 在 JSON 文件中添加以下代码片段：\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## 支持 `html!` 宏\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 扩展\n\n> 这是一个**正在进行中**的，**由社区维护**的项目！[请查看详细信息，并将相关的 bug 报告/问题/疑问直接发送到扩展的存储库](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 扩展 [可以在 VSC Marketplace 上找到](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)，提供语法高亮、重命名、悬停等功能。\n\nEmmet 支持应该可以直接使用，如果不能，请回退到编辑 `settings.json` 文件：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> 下面的配置适用于 [LazyVim](https://www.lazyvim.org) 配置和 lazy.vim 插件，请在 `lua/plugins/nvim-lspconfig.lua` 中创建一个文件（或更新您的 `lspconfig`）：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/getting-started/examples.mdx",
    "content": "---\ntitle: '示例'\n---\n\nYew 仓库包含许多[示例]（维护状态各异）。\n我们建议浏览它们以了解如何使用框架的不同功能。\n我们也欢迎拉取请求和问题，以便在它们不可避免地被忽略并需要一些帮助 ♥️ 时使用。\n\n有关更多详细信息，包括示例列表，请参阅[README]。\n\n:::note\n大多数示例都有一个可以在 https://examples.yew.rs/< example_name > 找到的在线部署。\n在各自的子文件夹中的 README 页面上点击它们的徽章以导航到在线演示。\n:::\n\n[示例列表]: https://github.com/yewstack/yew/tree/master/examples\n[示例文档 README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/getting-started/introduction.mdx",
    "content": "---\ntitle: '开始使用'\n---\n\n你需要一些工具来编译、构建、打包和调试你的 Yew 应用程序。在最开始，我们建议使用 [Trunk](https://trunkrs.dev/)。Trunk 是一个用于 Rust 的 WASM Web 应用程序打包工具。\n\n## 安装 Rust\n\n要安装 Rust，请按照[官方说明](https://www.rust-lang.org/tools/install)。\n\n:::important\nYew 支持的最低 Rust 版本（MSRV）是 `1.84.0`。旧版本将无法编译。您可以使用 `rustup show`（在“active toolchain”下）或 `rustc --version` 检查您的工具链版本。要更新您的工具链，请运行 `rustup update`。\n:::\n\n## 安装 WebAssembly 目标\n\nRust 可以为不同的“目标”（例如不同的处理器）编译源代码。用于基于浏览器的 WebAssembly 的编译目标称为 `wasm32-unknown-unknown`。以下命令将向您的开发环境添加 WebAssembly 目标。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## 安装 Trunk\n\nTrunk 是推荐的用于管理部署和打包的工具，并在整个文档和示例中使用。\n\n```shell\n# 需要注意的是，这可能需要一段时间来安装，因为它会从头开始编译所有内容\n# Trunk 还为许多主要的包管理器提供了预构建的二进制文件\n# 有关更多详细信息，请参见 https://trunkrs.dev/#install\ncargo install --locked trunk\n```\n\n### 其他选项\n\n除了 Trunk 之外，还有其他选项可用于打包 Yew 应用程序。您可能想尝试以下选项之一：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (仍在早期开发阶段)\n\n## 下一步\n\n设置好开发环境后，您现在可以继续阅读文档。如果您喜欢通过动手实践来学习，我们建议您查看我们的[教程](../tutorial)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\n一个关于如何最好地将 CSS 支持集成到 Yew 中的讨论可以在这里找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n这里包含了很多关于如何最好地将 CSS 支持集成到 Yew 中的讨论。\n\n目前，我们采用的方法是鼓励开发者在采用最流行的系统之前构建许多系统。\n\n社区目前正在开发几个项目，以便为项目添加样式。以下是其中的一些：\n\n#### 组件库\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - 一个没有任何 JavaScript 依赖的 Yew 样式框架。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design 组件。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS 组件。\n- [Yewtify](https://github.com/yewstack/yewtify) – 在 Yew 中实现 Vuetify 框架提供的功能。\n\n#### 样式解决方案\n\n- [stylist](https://github.com/futursolo/stylist-rs) - 用于 WebAssembly 应用程序的 CSS-in-Rust 样式解决方案。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind 实用类。\n\n:::important 改进文档\n如果您正在开发一个为 Yew 添加样式的项目，请提交一个 PR 将自己添加到这个列表中！\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/more/debugging.mdx",
    "content": "---\ntitle: '调试'\n---\n\n## 意外终止 (Panics)\n\nYew 会自动在浏览器控制台中输出意外终止日志。\n\n## 控制台日志\n\n在 JavaScript 中，`console.log()` 用于输出到浏览器控制台。以下是一些 Yew 的选项。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate 与 [`log`](https://crates.io/crates/log) crate 集成，以将日志级别、源行和文件名发送到浏览器控制台。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\n这个 crate 是 Gloo 的一部分，提供了对浏览器 API 的 Rust 包装。`log!` 宏可以直接接受 `JsValue`，比 `wasm_logger` 更容易使用。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` 可以与 [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) 一起使用，将消息输出到浏览器控制台。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## 调试组件生命周期\n\n[`tracing`](https://crates.io/crates/tracing) 可以用于收集与组件生命周期相关的事件信息。`tracing` 还带有一个 `log` 支持的特性标志，可以与 `wasm-logger` 很好地集成。\n\n[编译时过滤器](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) 可以用于调整详细程度或禁用日志记录，这应该会导致更小的 Wasm 文件。\n\n## 源映射 (Source Maps)\n\n有一些支持 [源映射](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf)。但是，需要一些配置。\n\n## 过去的文章\n\n以下是一些关于 Rust 中 WebAssembly 调试状态的过去文章。它们可能是有趣的阅读。\n\n\\[Dec 2019\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 这些工作还有很多要做。例如，在工具方面，Emscripten（Binaryen）和 wasm-pack（wasm-bindgen）尚未支持在它们执行的转换上更新 DWARF 信息。\n\n\\[2020\\] [Rust Wasm 调试指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸的是，WebAssembly 的调试能力仍然不成熟。在大多数 Unix 系统上，[DWARF](http://dwarfstd.org/) 用于编码调试器需要提供运行中程序的源级检查的信息，就连在 Windows 上有一种编码类似信息的替代格式。但目前，WebAssembly 没有相应的格式。\n\n\\[2019\\] [Rust Wasm 路线图](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 调试很棘手，因为很多情况不在这个工作组的掌控之中，而是取决于 WebAssembly 标准化机构和实现浏览器开发者工具的人。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/more/deployment.mdx",
    "content": "---\ntitle: '部署'\ndescription: '部署 Yew 应用程序'\n---\n\n当您准备将 Yew 应用程序部署到服务器时，您有多种部署方案可以选择。\n\n`trunk build --release` 会以发布模式构建您的应用程序。设置您的 HTTP 服务器，以便在访问您的站点时提供 `index.html`，并且对于静态路径（例如 `index_<hash>.js` 和 `index_bg_<hash>.wasm`）的请求，应该从 trunk 生成的 dist 目录中提供相应的内容。\n\n:::important 有关 `trunk serve --release`\n不要在生产环境中使用 `trunk serve --release` 来提供您的应用程序。\n它只应该用于在开发过程中测试发布版本构建。\n:::\n\n## 服务器配置\n\n### 将 `index.html` 作为回退提供\n\n如果应用程序使用了 [Yew 路由](concepts/router.mdx)，您必须配置服务器在请求不存在的文件时返回 `index.html`。\n\n具有 Yew 路由的应用程序被构建为 [单页应用程序 (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA)。当用户从正在运行的客户端导航到 URL 时，路由器会解释 URL 并路由到该页面。\n\n但是在刷新页面或在地址栏中输入 URL 时，这些操作都是由浏览器本身处理的，而不是由正在运行的应用程序处理。浏览器直接向服务器请求该 URL，绕过了路由器。错误配置的服务器会返回 404 - 未找到 状态。\n\n通过返回 `index.html`，应用程序会像通常一样加载，就好像请求是 `/`，直到路由器注意到路由是 `/show/42` 并显示相应的内容。\n\n### 为 Web Assembly 资源配置正确的 MIME 类型。\n\nWASM 文件必须使用 `application/wasm` MIME 类型设置 [Content-Type 头](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。\n\n大多数服务器和托管服务默认已经这样做。如果您的服务器没有这样做，请查阅其文档。在大多数 Web 浏览器中，错误的 MIME 类型会导致类似以下的错误：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 为相对路径构建\n\n默认情况下，trunk 会假定您的站点在 `/` 处提供，并相应地构建站点。可以通过在 `index.html` 文件中添加 `<base data-trunk-public-url />` 来覆盖此行为。Trunk 会重写此标签以包含传递给 `--public-url` 的值。Yew 路由会自动检测 `<base />` 的存在并适当处理。\n\n## 使用环境变量自定义行为\n\n通常使用环境变量来自定义构建环境。由于应用程序在浏览器中运行，我们无法在运行时读取环境变量。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) 宏可以在编译时获取环境变量的值。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/more/roadmap.mdx",
    "content": "---\ntitle: '路线图'\ndescription: 'Yew 框架的计划功能路线图'\n---\n\n## 优先级\n\n框架即将推出的功能和重点的优先级由社区决定。\n在 2020 年春季，我们发送了一份开发者调查，以收集关于项目方向的反馈。\n您可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到调查摘要。\n\n:::note\n所有主要倡议的状态都可以在 Yew Github [项目看板](https://github.com/yewstack/yew/projects) 上跟踪\n:::\n\n## 重点\n\n1. 最受欢迎的功能\n2. 生产就绪\n3. 文档\n4. 痛点\n\n### 最受欢迎的功能\n\n1. [函数组件](https://github.com/yewstack/yew/projects/3)\n2. [组件库](https://github.com/yewstack/yew/projects/4)\n3. 更好的状态管理\n4. [服务器端渲染](https://github.com/yewstack/yew/projects/5)\n\n### 生产就绪所需的问题\n\n- 提高 Yew 测试覆盖率\n- 减小二进制文件大小\n- [性能基准测试](https://github.com/yewstack/yew/issues/5)\n\n### 文档\n\n- 创建教程\n- 简化项目设置\n\n### 痛点\n\n- [组件样板](https://github.com/yewstack/yew/issues/830)\n- [代理](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/more/testing.mdx",
    "content": "---\ntitle: '测试应用'\ndescription: '测试你的应用'\n---\n\n:::info\n我们正在努力让测试组件变得更容易，但目前仍在进行中。\n\n在 GitHub 仓库中可以找到对 [浅渲染](https://github.com/yewstack/yew/issues/1413) 的支持。\n:::\n\n## 快照测试\n\nYew 提供了 `yew::tests::layout_tests` 模块来方便组件的快照测试。\n\n:::important 改进文档\n我们需要帮助，以改进快照测试的文档。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM 工作组维护了一个叫做 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) 的 crate，\n它允许你以类似于内置的 `#[test]` 过程宏的方式在浏览器中运行测试。\n有关此模块的更多信息，请参阅 [Rust Wasm 工作组的文档](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22/tutorial/index.mdx",
    "content": "---\ntitle: '教程'\nslug: /tutorial\n---\n\n## 介绍\n\n在这个实践教程中，我们将学习如何使用 Yew 构建 Web 应用程序。\n**Yew** 是一个现代的 [Rust](https://www.rust-lang.org/) 框架，用于使用 [WebAssembly](https://webassembly.org/) 构建前端 Web 应用程序。\nYew 通过利用 Rust 强大的类型系统，鼓励可重用、可维护和良好结构化的架构。\n一个庞大的社区创建的库生态系统，称为 Rust 中的 [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)，为常用模式（如状态管理）提供了组件。\nRust 的包管理器 [Cargo](https://doc.rust-lang.org/cargo/) 允许我们利用 [crates.io](https://crates.io) 上提供的大量 crate，例如 Yew。\n\n### 我们将要构建的内容\n\nRustconf 是 Rust 社区每年举办的星际聚会。\nRustconf 2020 有大量的演讲，提供了大量的信息。\n在这个实践教程中，我们将构建一个 Web 应用程序，帮助其他 Rustaceans 了解这些演讲并从一个页面观看它们。\n\n## 设置\n\n### 先决条件\n\n这个教程假设您已经熟悉 Rust。如果您是 Rust 的新手，免费的 [Rust 书](https://doc.rust-lang.org/book/ch00-00-introduction.html) 为初学者提供了一个很好的起点，并且即使对于有经验的 Rust 开发人员来说，它仍然是一个很好的资源。\n\n确保安装了最新版本的 Rust，方法是运行 `rustup update` 或者[安装 Rust](https://www.rust-lang.org/tools/install)。\n\n安装 Rust 后，您可以使用 Cargo 运行以下命令安装 `trunk`：\n\n```bash\ncargo install trunk\n```\n\n我们还需要添加 WASM 构建目标，运行以下命令：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### 设置项目\n\n首先，创建一个新的 cargo 项目：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\n为了验证 Rust 环境是否设置正确，使用 cargo 构建工具运行初始项目。\n在关于构建过程的输出之后，您应该看到预期的 \"Hello, world!\" 消息。\n\n```bash\ncargo run\n```\n\n## 我们的第一个静态页面\n\n为了将这个简单的命令行应用程序转换为一个基本的 Yew web 应用程序，需要进行一些更改。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在构建一个应用程序，你只需要 `csr` 特性。它将启用 `Renderer` 和所有与客户端渲染相关的代码。\n\n如果你正在制作一个库，请不要启用此特性，因为它会将客户端渲染逻辑拉入服务器端渲染包中。\n\n如果你需要 Renderer 进行测试或示例，你应该在 `dev-dependencies` 中启用它。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n现在，让我们在项目的根目录创建一个 `index.html`。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 启动开发服务器\n\n运行以下命令构建并在本地提供应用程序。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n删除选项 '--open' 以在运行 `trunk serve` 后不打开默认浏览器。\n:::\n\nTrunk 将在您修改任何源代码文件时实时重新构建您的应用程序。\n默认情况下，服务器将在地址 '127.0.0.1' 的端口 '8080' 上监听 => [http://localhost:8080](http://127.0.0.1:8080)。\n要更改这部分配置，请创建以下文件并根据需要进行编辑：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 局域网上的监听地址\naddress = \"127.0.0.1\"\n# 广域网上的监听地址\n# address = \"0.0.0.0\"\n# 监听的端口\nport = 8000\n```\n\n如果您感兴趣，您可以运行 `trunk help` 和 `trunk help <subcommand>` 以获取更多关于正在进行的流程的详细信息。\n\n### 恭喜\n\n您现在已经成功设置了 Yew 开发环境，并构建了您的第一个 Yew Web 应用程序。\n\n## 构建 HTML\n\nYew 利用了 Rust 的过程宏，并为我们提供了一种类似于 JSX（JavaScript 的扩展，允许您在 JavaScript 中编写类似 HTML 的代码）的语法来创建标记。\n\n### 转换为经典 HTML\n\n由于我们已经对我们的网站长什么样有了一个很好的想法，我们可以简单地将我们的草稿转换为与 `html!` 兼容的表示。如果您习惯于编写简单的 HTML，那么您在 `html!` 中编写标记时应该没有问题。需要注意的是，这个宏与 HTML 有一些不同之处：\n\n1. 表达式必须用大括号（`{ }`）括起来\n2. 只能有一个根节点。如果您想要在不将它们包装在容器中的情况下拥有多个元素，可以使用空标签/片段（`<> ... </>`）\n3. 元素必须正确关闭。\n\n我们想要构建一个布局，原始 HTML 如下：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\n现在，让我们将这个 HTML 转换为 `html!`。将以下代码片段输入（或复制/粘贴）到 `app` 函数的主体中，以便函数返回 `html!` 的值\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\n刷新浏览器页面，您应该看到以下输出：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### 在标记中使用 Rust 语言结构\n\n在 Rust 中编写标记的一个很大的优势是，我们在标记中获得了 Rust 的所有优点。\n现在，我们不再在 HTML 中硬编码视频列表，而是将它们定义为 `Vec` 的 `Video` 结构体。\n我们创建一个简单的 `struct`（在 `main.rs` 或我们选择的任何文件中）来保存我们的数据。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n接下来，我们将在 `app` 函数中创建这个结构体的实例，并使用它们来替代硬编码的数据：\n\n```rust\nuse website_test::tutorial::Video; // 换成你自己的路径\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\n为了显示它们，我们需要将 `Vec` 转换为 `Html`。我们可以通过创建一个迭代器，将其映射到 `html!` 并将其收集为 `Html` 来实现：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\n在列表项上使用键有助于 Yew 跟踪列表中哪些项发生了变化，从而实现更快的重新渲染。[始终建议在列表中使用键](/concepts/html/lists.mdx#keyed-lists)。\n:::\n\n最后，我们需要用从数据创建的 `Html` 替换硬编码的视频列表：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## 组件\n\n组件是 Yew 应用程序的构建块。通过组合组件（可以由其他组件组成），我们构建我们的应用程序。通过为可重用性构建组件并保持它们的通用性，我们将能够在应用程序的多个部分中使用它们，而无需重复代码或逻辑。\n\n到目前为止我们一直在使用的 `app` 函数是一个组件，称为 `App`。它是一个“函数式组件”。\n\n1. 结构体组件\n2. 函数式组件\n\n在本教程中，我们将使用函数式组件。\n\n现在，让我们将 `App` 组件拆分为更小的组件。我们首先将视频列表提取到自己的组件中。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n注意我们的 `VideosList` 函数组件的参数。函数组件只接受一个参数，该参数定义了它的 \"props\"（\"properties\" 的缩写）。Props 用于从父组件传递数据到子组件。在这种情况下，`VideosListProps` 是一个定义 props 的结构体。\n\n:::important\n用于 props 的结构体必须通过派生实现 `Properties`。\n:::\n\n为了使上面的代码编译通过，我们需要修改 `Video` 结构体如下：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n现在，我们可以更新我们的 `App` 组件以使用 `VideosList` 组件。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n通过查看浏览器窗口，我们可以验证列表是否按预期呈现。我们已经将列表的渲染逻辑移动到了它的组件中。这缩短了 `App` 组件的源代码，使我们更容易阅读和理解。\n\n### 使应用可以交互\n\n这里的最终目标是显示所选视频。为了做到这一点，`VideosList` 组件需要在选择视频时“通知”其父组件，这是通过 `Callback` 完成的。这个概念称为“传递处理程序”。我们修改其 props 以接受一个 `on_click` 回调：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n然后我们修改 `VideosList` 组件以将所选视频传递给回调。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n接下来，我们需要修改 `VideosList` 的使用以传递该回调。但在这样做之前，我们应该创建一个新的组件 `VideoDetails`，当点击视频时才会显示。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n现在，修改 `App` 组件以在选择视频时显示 `VideoDetails` 组件。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n现在不用担心 `use_state`，我们稍后会回到这个问题。注意我们用 `{ for details }` 提取列表数据的技巧。\n`Option<_>` 实现了 `Iterator`，所以我们可以使用特殊的 `{ for ... }` 语法来逐个显示 `Iterator` 返回的唯一元素，而这[由 `html!` 宏支持](concepts/html/lists)。\n\n### 处理状态\n\n还记得之前使用的 `use_state` 吗？那是一个特殊的函数，称为 \"hook\"。Hooks 用于 \"hook\" 到函数组件的生命周期中并执行操作。您可以在[这里](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)了解更多关于这个 hook 和其他 hook 的信息。\n\n:::note\n结构体组件的行为不同。请查看[文档](advanced-topics/struct-components/introduction.mdx)了解有关这些的信息。\n:::\n\n## 获取数据（使用外部 REST API）\n\n在真实的应用程序中，数据通常来自 API 而不是硬编码。让我们从外部源获取我们的视频列表。为此，我们需要添加以下 crate：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  用于进行 fetch 调用。\n- [`serde`](https://serde.rs) 和其派生特性\n  用于反序列化 JSON 响应\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  用于将 Rust 的 Future 作为 Promise 执行\n\n让我们更新 `Cargo.toml` 文件中的依赖项：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n在选择依赖项时，请确保它们与 `wasm32` 兼容！否则，您将无法运行您的应用程序。\n:::\n\n更新 `Video` 结构体以派生 `Deserialize` 特性：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n作为最后一步，我们需要更新我们的 `App` 组件，以便进行 fetch 请求，而不是使用硬编码的数据\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\n我们在这里使用 `unwrap`，因为这是一个演示应用程序。在真实的应用程序中，您可能希望有[适当的错误处理](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)。\n:::\n\n现在，查看浏览器，看看一切是否按预期工作……如果不是因为 CORS 的话。为了解决这个问题，我们需要一个代理服务器。幸运的是 trunk 提供了这个功能。\n\n更新这些行：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n现在，使用以下命令重新运行服务器：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\n刷新网页，一切应该按预期工作。\n\n## 总结\n\n恭喜！您已经创建了一个从外部 API 获取数据并显示视频列表的 Web 应用程序。\n\n## 接下来\n\n这个应用程序离完美或有用还有很长的路要走。在完成本教程后，您可以将其作为探索更高级主题的起点。\n\n### 样式\n\n我们的应用程序看起来非常丑陋。没有 CSS 或任何样式。不幸的是，Yew 没有提供内置的样式组件。请查看 [Trunk 的 assets](https://trunkrs.dev/assets/)，了解如何添加样式表。\n\n### 更多依赖库\n\n我们的应用程序只使用了很少的外部依赖。有很多 crate 可以使用。请查看[外部库](/community/external-libs)以获取更多详细信息。\n\n### 了解更多关于 Yew\n\n阅读我们的[官方文档](../getting-started/introduction.mdx)。它更详细地解释了许多概念。要了解有关 Yew API 的更多信息，请查看我们的[API 文档](https://docs.rs/yew)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.22.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.22\",\n    \"description\": \"The label for version 0.22\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"从零开始\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"核心概念\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew 核心概念\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"了解 Yew 的重要概念！\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"函数式组件\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"高级主题\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"高级主题\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"了解 Yew 的更多内部细节！\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"更多\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"杂项\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"迁移指南\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Yew 中的基本 Web 技术\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew 对基本 Web 技术的看法\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew 主要基于将可重用的 UI 部件所需的所有内容放在一个地方 - rust 文件的想法。但也力求保持与技术的原始外观接近。进一步探索，以充分理解我们对这些陈述的含义：\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"钩子\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"结构化组件\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/children.mdx",
    "content": "---\ntitle: '子组件'\n---\n\n:::caution\n\n检查和操作 `Children` 往往会导致应用程序中令人惊讶且难以解释的行为。这可能导致边缘情况，并且通常不会产生预期的结果。如果您尝试操作 `Children`，则应考虑其他方法。\n\nYew 支持将 `Html` 用作子组件属性的类型。如果您不需要 `Children` 或 `ChildrenRenderer`，则应使用 `Html` 作为子组件。它没有 `Children` 的缺点，并且性能开销较低。\n\n:::\n\n## 通用用法\n\n*大多数情况下，*当允许组件具有子组件时，您不关心组件具有的子组件的类型。在这种情况下，下面的示例就足够了。\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## 高级用法\n\n### 类型化子组件\n\n在您希望将一种类型的组件作为子组件传递给您的组件的情况下，您可以使用 `yew::html::ChildrenWithProps<T>`。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## 带有属性的嵌套子组件\n\n如果包含组件对其子组件进行了类型化，则可以访问和更改嵌套组件的属性。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 枚举类型的子组件\n\n当然，有时您可能需要将子组件限制为几种不同的组件。在这些情况下，您必须更深入地了解 Yew。\n\n这里使用 [`derive_more`](https://github.com/JelteF/derive_more) 来提供更好的人机工程学。如果您不想使用它，您可以为每个变体手动实现 `From`。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 现在，我们实现 `Into<Html>`，以便 yew 知道如何渲染 `Item`。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### 可选类型的子组件\n\n您还可以具有特定类型的单个可选子组件：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... 页面内容\n            </div>\n        }\n    }\n}\n\n// 页面组件可以选择是否附带侧边栏：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // 附带侧边栏的页面\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // 不附带侧边栏的页面\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## 进一步阅读\n\n- 有关此模式的真实示例，请查阅 yew-router 的源代码。有关更高级的示例，请查看 yew 存储库中的[相关示例清单](https://github.com/yewstack/yew/tree/master/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '工作原理'\ndescription: '关于框架的底层细节'\n---\n\n# 底层库的内部细节\n\n## `html!` 宏的内部\n\n`html!` macro 会将使用类似 HTML 的自定义语法编写的代码转换为有效的 Rust 代码。使用这个宏对于开发 Yew 应用程序并不是必需的，但是是推荐的。这个宏生成的代码使用了 Yew 的公共库 API，如果你愿意的话，可以直接使用。请注意，有些方法是有意未记录的，以避免意外的误用。随着 `yew-macro` 的每次更新，生成的代码将会更加高效，并且可以处理任何破坏性的更改，而不需要对 `html!` 语法进行很多（如果有的话）修改。\n\n由于 `html!` 宏允许您以声明式的风格编写代码，因此您的 UI 布局代码将与为页面生成的 HTML 非常相似。随着您的应用程序变得更加交互式，您的代码库变得更大，这种方式变得越来越有用。与手动编写所有操作 DOM 的代码相比，宏会为您处理好这一切。\n\n使用 `html!` 宏可能会让人感到非常神奇，但它并没有什么可隐藏的。如果您对它的工作原理感到好奇，可以尝试展开您程序中的 `html!` 宏调用。有一个有用的命令叫做 `cargo expand`，它允许您查看 Rust 宏的展开。`cargo expand` 并不是默认随 `cargo` 一起提供的，所以如果您还没有安装它，您需要使用 `cargo install cargo-expand` 来安装它。[Rust-Analyzer](https://rust-analyzer.github.io/) 也提供了一种[从 IDE 中获取宏输出的机制](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)。\n\n`html!` 宏的输出通常非常简洁！这是一个特性：机器生成的代码有时可能会与应用程序中的其他代码冲突。为了防止问题，`proc_macro` 遵循了“卫生”规则。一些例子包括：\n\n1. 为了确保正确引用 Yew 包，宏生成的代码中使用 `::yew::<module>`，而不是直接使用 `yew::<module>`。这也是为什么调用 `::alloc::vec::Vec::new()` 而不是直接调用 `Vec::new()`。\n2. 由于可能存在 trait 方法名称冲突，使用 `<Type as Trait>` 来确保我们使用的是正确的 trait 成员。\n\n## 什么是虚拟 DOM？\n\nDOM（\"文档对象模型\"）是由浏览器管理的 HTML 内容的表示。\"虚拟\" DOM 只是 DOM 的一个内存中的副本。管理虚拟 DOM 会导致更高的内存开销，但可以通过避免或延迟使用浏览器 API 来实现批处理和更快的读取。\n\n在内存中拥有 DOM 的副本对于促进使用声明式 UI 的库是有帮助的。与需要特定代码来描述如何根据用户事件修改 DOM 不同，库可以使用一种通用的方法来进行 DOM \"diffing\"。当 Yew 组件更新并希望更改其呈现方式时，Yew 库将构建虚拟 DOM 的第二个副本，并直接将其与镜像当前屏幕上的内容的虚拟 DOM 进行比较。两者之间的 \"diff\"（差异）可以分解为增量更新，并与浏览器 API 一起应用。一旦更新应用，旧的虚拟 DOM 副本将被丢弃，新的副本将被保存以供将来的差异检查。\n\n这种 \"diff\" 算法可以随着时间的推移进行优化，以提高复杂应用程序的性能。由于 Yew 应用程序是通过 WebAssembly 运行的，我们相信 Yew 在未来采用更复杂的算法方面具有竞争优势。\n\nYew 的虚拟 DOM 与浏览器 DOM 不完全一一对应。它还包括用于组织 DOM 元素的 \"列表\" 和 \"组件\"。列表可以简单地是元素的有序列表，但也可以更强大。通过为每个列表元素添加 \"key\" 注解，应用程序开发人员可以帮助 Yew 进行额外的优化，以确保在列表更改时，计算差异更新所需的工作量最小。同样，组件提供了自定义逻辑，指示是否需要重新渲染，以帮助提高性能。\n\n## Yew 调度器和组件范围的事件循环\n\n_贡献文档 - 深入解释 `yew::scheduler` 和 `yew::html::scope` 的工作原理_\n\n## 进一步阅读\n\n- [Rust 手册中关于宏的更多信息](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` 的更多信息](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` 的 API 文档](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/immutable.mdx",
    "content": "---\ntitle: '不可变类型'\ndescription: 'Yew 的不可变数据结构'\n---\n\n## 什么是不可变类型？\n\n这些类型是您可以实例化但永远不会更改值的类型。为了更新值，您必须实例化一个新值。\n\n## 为什么使用不可变类型？\n\n与 React 一样，属性是从祖先传播到子代的。这意味着属性在每个组件更新时必须存在。这就是为什么属性应该——理想情况下——很容易克隆。为了实现这一点，我们通常将事物包装在 `Rc` 中。\n\n不可变类型非常适合保存属性的值，因为它们可以在从组件传递到组件时以很低的成本克隆。\n\n## 常见的不可变类型\n\nYew 推荐使用来自 `implicit-clone` crate 的以下不可变类型：\n\n- `IString`（在 Yew 中别名为 `AttrValue`）- 用于字符串而不是 `String`\n- `IArray<T>` - 用于数组/向量而不是 `Vec<T>`\n- `IMap<K, V>` - 用于映射而不是 `HashMap<K, V>`\n\n这些类型是引用计数（`Rc`）或静态引用，使它们的克隆成本非常低。\n\n## 进一步阅读\n\n- [不可变示例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '优化 & 最佳实践'\nsidebar_label: Optimizations\ndescription: '让您的应用程序获得最佳性能'\n---\n\n## 使用智能指针\n\n**注意：如果您对本节中使用的某些术语感到困惑，Rust 手册中有一个有用的[关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)。**\n\n为了避免在重新渲染时克隆大量数据以创建 props，我们可以使用智能指针，只克隆对数据的引用而不是数据本身。如果您在 props 和子组件中传递与相关数据的引用而不是实际数据，您可以避免在需要修改数据的子组件中克隆任何数据，您可以使用 `Rc::make_mut` 来克隆并获得要更改的数据的可变引用。\n\n这在 `Component::changed` 中带来了更多好处，可以确定 prop 更改是否需要组件重新渲染。这是因为可以比较指针地址（即数据存储在机器内存中的位置）而不是数据的值；如果两个指针指向相同的数据，则它们指向的数据的值必须相同。请注意，反之可能不成立！即使两个指针地址不同，底层数据仍可能相同 - 在这种情况下，您应该比较底层数据。\n\n要进行此比较，您需要使用 `Rc::ptr_eq` 而不仅仅使用 `PartialEq`（在使用相等运算符 `==` 比较数据时自动使用）。Rust 文档有关于 `Rc::ptr_eq` 的[更多细节](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\n这种优化对于不实现 `Copy` 的数据类型最有用。如果您可以廉价地复制数据，则没有必要将其放在智能指针后面。对于可能是数据密集型的结构，如 `Vec`、`HashMap` 和 `String`，使用智能指针可能会带来性能改进。\n\n如果值从不被子组件更新，则此优化效果最佳，如果父组件很少更新，则效果更佳。这使得 `Rc<_>` 是在纯组件中包装属性值的一个不错的选择。\n\n但是，必须注意，除非您需要在子组件中自己克隆数据，否则这种优化不仅是无用的，而且还增加了不必要的引用计数成本。Yew 中的 props 已经是引用计数的，内部不会发生数据克隆。\n\n## 渲染函数\n\n出于代码可读性的原因，将 `html!` 的部分重复代码迁移到专门分割出来的函数中通常是有意义的。这不仅使您的代码更易读，减少了代码缩进，而且还鼓励良好的设计模式——特别是围绕构建可组合应用程序，这些函数可以在多个地方调用，从而减少代码量。\n\n## 纯组件\n\n纯组件是不会改变其状态的组件，只显示内容并将消息传播到普通的可变组件。它们与视图函数的不同之处在于，它们可以在 `html!` 宏中使用组件语法（`<SomePureComponent />`）而不是表达式语法（`{some_view_function()}`），并且根据其实现，它们可以被记忆化（这意味着一旦调用函数，其值就会被“保存”，因此如果多次使用相同的参数调用它，则不必重新计算其值，只需从第一个函数调用返回保存的值）- 防止相同的 props 重新渲染。Yew 在内部比较 props，因此仅在 props 更改时重新渲染 UI。\n\n## 使用工作区减少编译时间\n\nYew 的最大缺点是编译所需的时间很长。编译项目所需的时间似乎与传递给 `html!` 宏的代码数量有关。对于较小的项目，这似乎不是什么问题，但对于较大的应用程序，将代码拆分到多个 crate 中以最小化编译器为应用程序所做的工作量是有意义的。\n\n一种可能的方法是使您的主 crate 处理路由/页面选择，然后为每个页面创建一个不同的 crate，其中每个页面可以是不同的组件或只是生成 `Html` 的大函数。存储在包含应用程序不同部分的 crate 之间的代码可以存储在项目依赖的单独 crate 中。在最理想的情况下，您从在每次编译时重新构建所有代码到仅重新构建主 crate 和一个页面 crate。在最坏的情况下，如果您在“common” crate 中编辑了某些内容，您将回到起点：编译依赖于该常用共享 crate 的所有代码，这可能是其他所有内容。\n\n如果您的主 crate 太重，或者您想快速迭代一个深度嵌套的页面（例如。在另一个页面上渲染的页面），您可以使用示例 crate 创建主页面的简化实现，并额外渲染您正在处理的组件。\n\n## 减小二进制文件大小\n\n- 优化 Rust 代码\n- `cargo.toml`（定义发布配置文件）\n- 使用 `wasm-opt` 优化 wasm 代码\n\n**注意：有关减小二进制文件大小的更多信息，请参阅[Rust Wasm 手册](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)。**\n\n### Cargo.toml\n\n可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用设置来配置发布构建为更小。\n\n```toml, title=Cargo.toml\n[profile.release]\n# 让二进制文件尺寸更小些\npanic = 'abort'\n# 优化整个代码库（优化更好，但构建速度也会更慢）\ncodegen-units = 1\n# 优化尺寸（更激进的做法）\nopt-level = 'z'\n# 优化尺寸\n# opt-level = 's'\n# 使用程序整体分析时进行链接时优化\nlto = true\n```\n\n### 开发版 Cargo 配置\n\n您还可以从 Rust 和 cargo 的实验性开发版功能中获得额外的好处。要使用 `trunk` 的开发版工具链，请设置 `RUSTUP_TOOLCHAIN=\"nightly\"` 环境变量。然后，您可以在 `.cargo/config.toml` 中配置不稳定的 rustc 功能。请参考[不稳定功能]的文档，特别是关于[`build-std`]和[`build-std-features`]的部分，以了解配置。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# 需要 rust-src 组件。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不稳定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n开发版 Rust 编译器可能包含错误，例如[这个例子](https://github.com/yewstack/yew/issues/2696)，需要偶尔关注和调整。请谨慎使用这些实验性选项。\n:::\n\n### wasm-opt\n\n此外，可以优化 `wasm` 代码的大小。\n\nRust Wasm 手册中有关于减小 Wasm 二进制文件大小的部分：[缩小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用 `wasm-pack`，默认情况下会优化发布构建中的 `wasm` 代码\n- 直接在 `wasm` 文件上使用 `wasm-opt`\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 在 yew/examples/ 中 'minimal' 示例的构建大小\n\n注意：`wasm-pack` 结合了 Rust 和 Wasm 代码的优化。在此示例中，`wasm-bindgen` 未经任何 Rust 大小优化。\n\n| 工具链                      | 大小  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## 进一步阅读\n\n- [Rust 手册中关于智能指针的章节](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm 手册中关于减小二进制文件大小的信息](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust 配置文件的文档](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen 项目](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/portals.mdx",
    "content": "---\ntitle: '传送门 (Portals)'\ndescription: '将内容渲染到 DOM 树外的节点'\n---\n\n## 什么是 Portal？\n\n传送门 (Portal) 提供了一种将子元素渲染到父组件的 DOM 层次结构之外的 DOM 节点的方法。`yew::create_portal(child, host)` 返回一个 `Html` 值，它将 `child` 渲染为 `host` 元素的子元素，而不是在其父组件的层次结构下。\n\n## 用法\n\n传送门的典型用途包括模态对话框和悬停卡片，以及更多技术应用，例如控制元素的 [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) 的内容，将样式表附加到周围文档的 `<head>` 中，以及在 `<svg>` 的中央 `<defs>` 元素中收集引用的元素。\n\n请注意，`yew::create_portal` 是一个低级构建块。库应该使用它来实现更高级的 API，然后应用程序可以使用这些 API。例如，这里是一个简单的模态对话框，它将其 `children` 渲染到 `yew` 之外的一个元素中，该元素由 `id=\"modal_host\"` 标识。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## 事件处理\n\n传送门内部元素上发出的事件遵循虚拟 DOM 冒泡。也就是说，如果传送门被渲染为元素的子元素，那么该元素上的事件监听器将捕获从传送门内部分发出的事件，即使传送门将其内容渲染在实际 DOM 中的不相关位置。\n\n这使开发人员无需关心他们使用的组件是使用传送门实现的还是没有使用传送门实现的。无论如何，其子元素上触发的事件都会冒泡。\n\n已知问题是，从传送门到 **关闭** 的 shadow root 的事件将被分发两次，一次针对 shadow root 内部的元素，一次针对宿主元素本身。请记住，**打开** 的 shadow root 可以正常工作。如果这影响到您，请随时提交一个错误报告。\n\n## 进一步阅读\n\n- [传送门示例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: '服务端渲染'\ndescription: '在服务端渲染 Yew 组件。'\n---\n\n# 服务端渲染 (Server-Side Rendering)\n\n默认情况下，Yew 组件在客户端渲染。当用户访问一个网站时，服务器会发送一个骨架 HTML 文件，不包含任何实际内容，以及一个 WebAssembly 包给浏览器。所有内容都由 WebAssembly 包在客户端渲染。这被称为客户端渲染。\n\n这种方法对于大多数网站来说都是有效的，但有一些注意事项：\n\n1. 用户在整个 WebAssembly 包下载并完成初始渲染之前将看不到任何内容。这可能会导致在缓慢的网络上用户体验不佳。\n2. 一些搜索引擎不支持动态渲染的网页内容，而那些支持的搜索引擎通常会将动态网站排名较低。\n\n为了解决这些问题，我们可以在服务端渲染我们的网站。\n\n## 工作原理\n\nYew 提供了一个 `ServerRenderer` 来在服务端渲染页面。\n\n要在服务端渲染 Yew 组件，您可以使用 `ServerRenderer::<App>::new()` 创建一个渲染器，并调用 `renderer.render().await` 将 `<App />` 渲染为一个 `String`。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// 我们在使用 `flavor = \"current_thread\"` 以保证这个示例可以在 CI 中的 WASM 环境运行,\n// 如果你希望使用多线程的话，可以使用默认的 `#[tokio::main]` 宏\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // 打印: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## 组件生命周期\n\n与客户端渲染不同，组件的生命周期在服务端渲染时会有所不同。\n\n在组件成功第一次渲染为 `Html` 之前，除了 `use_effect` (和 `use_effect_with`) 之外的所有钩子都会正常工作。\n\n:::caution 浏览器接口不可用！\n\n浏览器相关的接口，如 `web_sys`，在组件在服务端渲染时是不可用的。如果您尝试使用它们，您的应用程序将会崩溃。您应该将需要这部分逻辑隔离在 `use_effect` 或 `use_effect_with` 中，因为在服务端渲染时它们无法也不应当执行。\n\n:::\n\n:::danger 结构化组件\n\n尽管可以在服务端渲染时使用结构化组件，但是在客户端安全逻辑（如函数组件的 `use_effect` 钩子）和生命周期事件之间没有明确的边界，并且生命周期事件的调用顺序与客户端不同。\n\n此外，结构化组件将继续接受消息，直到所有子组件都被渲染并调用了 `destroy` 方法。开发人员需要确保不会将可能传递给组件的消息链接到调用浏览器接口的逻辑。\n\n在设计支持服务端渲染的应用程序时，请尽量使用函数组件，除非您有充分的理由不这样做。\n\n:::\n\n## 服务端渲染期间的数据获取\n\n数据获取是服务端渲染和水合（hydration）期间的难点之一。\n\n传统做法中，当一个组件渲染时，它会立即可用（输出一个虚拟 DOM 以进行渲染）。当组件不需要获取任何数据时，这种方式是有效的。但是如果组件在渲染时想要获取一些数据会发生什么呢？\n\n过去，Yew 没有机制来检测组件是否仍在获取数据。数据获取客户端负责实现一个解决方案，以检测在初始渲染期间请求了什么，并在请求完成后触发第二次渲染。服务器会重复这个过程，直到在返回响应之前没有在渲染期间添加更多的挂起请求。\n\n这不仅浪费了 CPU 资源，因为重复渲染组件，而且数据客户端还需要提供一种方法，在水合过程中使在服务端获取的数据可用，以确保初始渲染返回的虚拟 DOM 与服务端渲染的 DOM 树一致，这可能很难实现。\n\nYew 采用了一种不同的方法，通过 `<Suspense />` 来解决这个问题。\n\n`<Suspense />` 是一个特殊的组件，当在客户端使用时，它提供了一种在组件获取数据（挂起）时显示一个回退 UI 的方法，并在数据获取完成后恢复到正常 UI。\n\n当应用程序在服务端渲染时，Yew 会等待组件不再挂起，然后将其序列化到字符串缓冲区中。\n\n在水合过程中，`<Suspense />` 组件中的元素保持未水合状态，直到所有子组件不再挂起。\n\n通过这种方法，开发人员可以轻松构建一个准备好进行服务端渲染的、与客户端无关的应用程序，并进行数据获取。\n\n## 渲染 `<head>` 标签\n\nSSR 中的一个常见需求是渲染动态 `<head>` 内容（例如 `<title>`、`<meta>`），使爬虫和社交预览在首次加载时能看到正确的元数据。\n\n`ServerRenderer` 只渲染组件树（通常对应文档的 body 部分），无法访问 `<head>`。因此，head 标签必须**在服务端、Yew 之外**生成，并在发送给客户端之前拼接到 HTML 模板中。\n\n[`ssr_router` 示例](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) 演示了这一模式：服务端从请求 URL 识别路由，生成适当的 `<title>` 和 `<meta>` 标签，并将它们注入到 Trunk 生成的 `index.html` 的 `</head>` 之前。\n\n:::info\n\n如需完全兼容 SSR 的第三方解决方案，请使用 [Bounce 的 `<Helmet/>` 组件](https://docs.rs/bounce/latest/bounce/helmet/index.html)。\n\n:::\n\n## SSR 水合（SSR Hydration）\n\n水合是将 Yew 应用程序连接到服务端生成的 HTML 文件的过程。默认情况下，`ServerRender` 打印可水合的 HTML 字符串，其中包含额外的信息以便于水合。当调用 `Renderer::hydrate` 方法时，Yew 不会从头开始渲染，而是将应用程序生成的虚拟 DOM 与服务器渲染器生成的 HTML 字符串进行协调。\n\n:::caution\n\n要成功对由 `ServerRenderer` 创建的 HTML 标记进行水合，客户端必须生成一个虚拟 DOM 布局，它与用于 SSR 的布局完全匹配，包括不包含任何元素的组件。如果您有任何只在一个实现中有用的组件，您可能希望使用 `PhantomComponent` 来填充额外组件的位置。\n:::\n\n:::warning\n\n只有在浏览器初始渲染 SSR 输出（静态 HTML）后，真实 DOM 与预期 DOM 匹配时，水合才能成功。如果您的 HTML 不符合规范，水合可能会失败。浏览器可能会更改不正确的 HTML 的 DOM 结构，导致实际 DOM 与预期 DOM 不同。例如，[如果您有一个没有 `<tbody>` 的 `<table>`，浏览器可能会向 DOM 添加一个 `<tbody>`](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## 水合期间的组件生命周期\n\n在水合期间，组件在创建后安排了 2 次连续的渲染。任何效果都是在第二次渲染完成后调用的。确保您的组件的渲染函数没有副作用是很重要的。它不应该改变任何状态或触发额外的渲染。如果您的组件当前改变状态或触发额外的渲染，请将它们移动到 `use_effect` 钩子中。\n\n在水合过程中，可以使用结构化组件进行服务端渲染，视图函数将在渲染函数之前被调用多次。直到调用渲染函数之前，DOM 被认为是未连接的，您应该防止在调用 `rendered()` 方法之前访问渲染节点。\n\n## 示例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // 对 body 元素下的所有内容进行水合，并移除尾部元素（如果有）。\n    renderer.hydrate();\n}\n```\n\n示例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n示例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## 单线程模式\n\nYew 支持以单线程进行服务端渲染，通过 `yew::LocalServerRenderer`。这种模式适用于像 WASI 这样的单线程环境。\n\n```rust\n// 使用 `wasm32-wasip1` 或 `wasm32-wasip2` 目标构建。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n示例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n如果您使用 `wasm32-unknown-unknown` 目标构建 SSR 应用程序，您可以使用 `not_browser_env` 功能标志来禁用 Yew 内部对特定于浏览器的 API 的访问。这在像 Cloudflare Worker 这样的无服务器平台上非常有用。\n:::\n\n:::caution\n\n服务端渲染目前是实验性的。如果您发现了一个 bug，[请在 GitHub 反馈](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回调函数 (Callbacks)'\n---\n\n## 回调函数 (Callbacks)\n\n回调函数是用于在 Yew 中与服务、代理和父组件进行通信的。在内部，它们的类型只是 `Fn` 包装在 `Rc` 中，以允许它们被克隆。\n\n它们有一个 `emit` 函数，该函数以其 `<IN>` 类型作为参数，并将其转换为其目标期望的消息。如果父组件中的回调函数作为 props 提供给子组件，子组件可以在其 `update` 生命周期钩子中调用回调函数的 `emit` 函数，以将消息发送回其父组件。在 `html!` 宏中作为 props 提供的闭包或函数会自动转换为回调函数。\n\n一个简单的回调函数的使用可能如下所示：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\n这个函数传递给 `callback` 必须始终带有一个参数。例如，`onclick` 处理程序需要一个接受 `MouseEvent` 类型参数的函数。然后处理程序可以决定应该发送什么类型的消息给组件。这个消息无条件地被安排在下一个更新循环中。\n\n如果你需要一个回调函数，它可能不需要引起更新，请使用 `batch_callback`。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 相关示例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高阶组件'\n---\n\n在一些情况下，结构组件不直接支持某些功能（例如 Suspense），或者使用某些功能需要大量的样板代码（例如 Context）。\n\n在这些情况下，建议创建高阶组件的函数组件。\n\n## 高阶组件定义\n\n高阶组件是不添加任何新 HTML 的组件，只是包装其他组件以提供额外功能。\n\n### 示例\n\n对 Context (上下文) 挂钩并将其传递给结构组件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '简介'\ndescription: 'Yew 中的组件'\n---\n\n## 什么是组件？\n\n组件是 Yew 的构建块。它们管理内部状态并可以将元素渲染到 DOM 中。通过为类型实现 `Component` trait 来创建组件。\n\n## 编写组件标记\n\nYew 使用虚拟 DOM 将元素渲染到 DOM 中。虚拟 DOM 树可以通过使用 `html!` 宏来构建。`html!` 使用的语法类似于 HTML，但并不相同。规则也更严格。它还提供了诸如条件渲染和使用迭代器渲染列表等超能力。\n\n:::info\n[了解更多关于 `html!` 宏，如何使用它以及它的语法](concepts/html/introduction.mdx)\n:::\n\n## 将数据传递给组件\n\nYew 组件使用 _props_ 在父组件和子组件之间通信。父组件可以将任何数据作为 props 传递给其子组件。Props 类似于 HTML 属性，但可以将任何 Rust 类型作为 props 传递。\n\n:::info\n[了解更多关于 props 的内容](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n对于除了父/子通信之外的其他通信，请使用 [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命周期'\ndescription: '组件及其生命周期钩子'\n---\n\n`Component` trait 有许多方法需要实现；Yew 会在组件的生命周期的不同阶段调用这些方法。\n\n## 生命周期\n\n:::important 改进文档\n`为文档做贡献：` [添加定制生命周期的组件示例](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命周期方法\n\n### Create\n\n当组件被创建时，它会从其父组件接收属性，并存储在传递给 `create` 方法的 `Context<Self>` 中。这些属性可以用来初始化组件的状态，而 \"link\" 可以用来注册回调或向组件发送消息。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体实现\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法允许您描述组件应该如何呈现到 DOM 中。使用 Rust 函数编写类似 HTML 的代码可能会变得非常混乱，因此 Yew 提供了一个名为 `html!` 的宏，用于声明 HTML 和 SVG 节点（以及将属性和事件监听器附加到它们）以及一种方便的方法来渲染子组件。这个宏在某种程度上类似于 React 的 JSX（除了编程语言的差异）。一个不同之处是 Yew 提供了一种类似 Svelte 的属性的简写语法，其中您可以只写 `{onclick}`，而不用写 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n就使用上的说明，请查看 [html! 指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 组件生命周期方法在 `view` 被调用并且 Yew 已经将结果渲染到 DOM 中后调用，但在浏览器刷新页面之前。当您想要执行只能在组件渲染元素后完成的操作时，此方法非常有用。还有一个名为 `first_render` 的参数，可以用来确定此函数是在第一次渲染时调用，还是在后续渲染时调用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n请注意，此生命周期方法不需要实现，并且默认情况下不会执行任何操作。\n:::\n\n### Update\n\n与组件的通信主要通过消息进行，这些消息由 `update` 生命周期方法处理。这允许组件根据消息更新自身，并确定是否需要重新渲染自身。消息可以由事件监听器、子组件、Agents、Services 或 Futures 发送。\n\n下面是 `update` 的一个实现示例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 重新渲染\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具体实现\n        }\n    }\n}\n```\n\n### Changed\n\n组件可能会被其父组件重新渲染。当这种情况发生时，它们可能会接收新的属性并需要重新渲染。这种设计通过仅更改属性的值来促进父子组件之间的通信。当属性更改时，有一个默认实现会重新渲染组件。\n\n### Destroy\n\n组件从 DOM 中卸载后，Yew 会调用 `destroy` 生命周期方法；如果您需要在组件被销毁之前执行清理操作，这是必要的。此方法是可选的，默认情况下不执行任何操作。\n\n### 无限循环\n\n无限循环在 Yew 的生命周期方法中是可能的，但只有在尝试在每次渲染后更新相同的组件时，当该更新还要求重新渲染组件时才会发生。\n\n下面是一个简单的示例：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // 我们总是请求在任何消息上重新渲染\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // 无论渲染什么都不重要\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // 请求使用此新消息更新组件\n        ctx.link().send_message(());\n    }\n}\n```\n\n让我们看看这里发生了什么：\n\n1. 使用 `create` 函数创建组件。\n2. 调用 `view` 方法，以便 Yew 知道要渲染到浏览器 DOM 中的内容。\n3. 调用 `rendered` 方法，使用 `Context` 链接安排更新消息。\n4. Yew 完成后渲染阶段。\n5. Yew 检查已安排的事件，并看到更新消息队列不为空，因此处理消息。\n6. 调用 `update` 方法，返回 `true` 表示发生了变化，组件需要重新渲染。\n7. 跳回到第 2 步。\n\n您仍然可以在 `rendered` 方法中安排更新，这通常是有用的，但是在这样做时，请考虑您的组件将如何终止此循环。\n\n## 关联类型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 类型用于在事件发生后向组件发送消息；例如，您可能希望在用户单击按钮或向下滚动页面时执行某些操作。因为组件通常需要响应多个事件，所以 `Message` 类型通常是一个枚举，其中每个变体都是要处理的事件。\n\n在组织代码库时，将 `Message` 类型的定义包含在定义组件的同一模块中是明智的。您可能会发现采用一致的命名约定来命名消息类型很有帮助。一个选项（尽管不是唯一的选项）是将类型命名为 `ComponentNameMsg`，例如，如果您的组件名为 `Homepage`，则可以将类型命名为 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示从其父组件传递给组件的信息。此类型必须实现 `Properties` trait（通常通过派生它）并可以指定某些属性是必需的还是可选的。在创建和更新组件时使用此类型。在组件的模块中创建一个名为 `Props` 的结构体，并将其用作组件的 `Properties` 类型是一种常见做法。通常将 \"properties\" 缩写为 \"props\"。由于 props 是从父组件传递下来的，因此应用程序的根组件通常具有 `Properties` 类型为 `()`。如果要为根组件指定属性，请使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多关于属性的信息](./properties)\n:::\n\n## 生命周期上下文\n\n所有组件生命周期方法都接受一个上下文对象。此对象提供了对组件作用域的引用，允许向组件发送消息并传递给组件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '属性 (Props)'\ndescription: '父子组件通信'\n---\n\n属性 (Properties) 使子组件和父组件之间能够进行通信。每个组件都有一个关联的属性类型，用于描述从父组件传递下来的内容。理论上，这可以是任何实现了 `Properties` 特性的类型，但实际上，它应该是一个结构体，其中每个字段代表一个属性。\n\n## 派生宏\n\n无需自己实现 `Properties` 特性，我们可以用 `#[derive(Properties)]` 来自动生成实现。派生 `Properties` 的类型也必须实现 `PartialEq`。\n\n### 字段属性\n\n在派生 `Properties` 时，默认情况下所有字段都是必需的。以下属性允许您为属性提供初始值，除非它们被设置为另一个值。\n\n:::tip\n属性不会在 Rustdoc 生成的文档中显示。您的属性的文档字符串应该说明一个属性是否是可选的，以及它是否有一个特殊的默认值。\n:::\n\n#### `#[prop_or_default]`\n\n使用字段类型的默认值使用 `Default` 特性来初始化属性值。\n\n#### `#[prop_or(value)]`\n\n使用 `value` 来初始化属性值。`value` 可以是返回字段类型的任何表达式。例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。\n\n#### `#[prop_or_else(function)]`\n\n调用 `function` 来初始化属性值。`function` 应该具有签名 `FnMut() -> T`，其中 `T` 是字段类型。\n\n## `PartialEq`\n\n`Properties` 需要实现 `PartialEq`。这样，Yew 才能比较它们，以便在它们发生变化时调用 `changed` 方法。\n\n## 使用 Properties 的性能开销\n\n内部属性是基于引用计数的指针存储的。这意味着只有一个指针被传递到组件树中的属性，以避免克隆整个属性所带来的昂贵性能开销。\n\n:::tip\n使用 `AttrValue`，这是我们提供的自定义属性值类型，这样就可以不用 String 或其他类似的需要克隆的类型。\n:::\n\n## 示例\n\n```rust\nuse yew::Properties;\n/// 从 virtual_dom 中导入 AttrValue\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标\n    href: AttrValue,\n    /// 还要注意我们使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 链接的颜色，默认为 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值为 None，则视图函数不会指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 当视图函数没有指定活动时，默认为 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n该宏使用与结构体表达式相同的语法，只是您不能使用属性或基本表达式 (`Foo { ..base }`)。类型路径可以直接指向属性 (`path::to::Props`)，也可以指向组件的关联属性 (`MyComp::Properties`)。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 链接必须有一个目标\n    href: AttrValue,\n    /// 还要注意我们使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 链接的颜色，默认为 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值为 None，则视图函数不会指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 当视图函数没有指定活动时，默认为 true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// 注意此函数接收 href 和 text 作为 String\n    /// 我们可以使用 `AttrValue::from` 将其转换为 `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '引用 (Refs)'\ndescription: '实现越界 DOM 访问'\n---\n\n`ref` 关键字可以在任何 HTML 元素或组件中使用，以获取附加到该元素的 DOM `Element`。这可以用于在 `view` 生命周期方法之外对 DOM 进行更改。\n\n这对于获取 canvas 元素或滚动到页面的不同部分很有用。例如，在组件的 `rendered` 方法中使用 `NodeRef` 允许您在从 `view` 渲染后对 canvas 元素进行绘制调用。\n\n语法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 相关示例\n\n- [节点引用](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: '作用域'\ndescription: '组件的作用域'\n---\n\n## 组件的 `Scope<_>` 接口\n\n`Scope` 是通过消息创建回调并更新自身的机制。我们通过在传递给组件的上下文对象上调用 `link()` 来获得对它的引用。\n\n### `send_message`\n\n这个函数可以向组件发送消息。消息由 `update` 方法处理，该方法确定组件是否应重新渲染。\n\n### `send_message_batch`\n\n这个函数可以同时向组件发送多个消息。这类似于 `send_message`，但是如果任何消息导致 `update` 方法返回 `true`，则组件将在处理完批处理中的所有消息后重新渲染。\n\n如果给定的参数向量为空，则此函数不执行任何操作。\n\n### `callback`\n\n创建一个回调，当执行时将向组件发送消息。在内部，它将使用提供的闭包返回的消息调用 `send_message`。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // 创建一个接受一些文本并将其作为 `Msg::Text` 消息变体发送到组件的回调。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上一行是多余的冗长，为了更清晰，可以简化为这样：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // 将 `Msg::Text(\"Hello World!\")` 发送到组件。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // 在这里放置 HTML\n        }\n    }\n}\n```\n\n### `batch_callback`\n\n创建一个回调，当执行时将向组件发送一批消息。与 `callback` 的区别在于，传递给此方法的闭包不必返回消息。相反，闭包可以返回 `Vec<Msg>` 或 `Option<Msg>`，其中 `Msg` 是组件的消息类型。\n\n`Vec<Msg>` 被视为一批消息，并在内部使用 `send_message_batch`。\n\n`Option<Msg>` 在值为 `Some` 时调用 `send_message`。如果值为 `None`，则不执行任何操作。这可以用于根据情况，不需要更新的情况。\n\n这是通过使用仅为这些类型实现的 `SendAsMessage` trait 实现的。您可以为自己的类型实现 `SendAsMessage`，这样可以在 `batch_callback` 中使用它们。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/agents.mdx",
    "content": "---\ntitle: '代理 (Agents)'\ndescription: \"Yew's 的代理系统\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n代理 (Agents) 是一种将任务卸载到 Web Workers 的方式。\n\n为了使代理能够并发运行，Yew 使用了 [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命周期\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## 代理的类型\n\n### 范围\n\n- 公开 - 在任何给定时间，公共代理的实例最多只有一个。桥梁将在 Web Worker 中生成或连接到已经生成的代理。当没有桥梁连接到此代理时，代理将消失。\n\n- 私有 - 为每个新的桥梁在 Web Worker 中生成一个新的代理。这对于将与浏览器通信的共享但独立的行为从组件中移出是很好的。当连接的桥梁被丢弃时，代理将消失。\n\n- 全局 \\(WIP\\)\n\n## 代理与组件之间的通信\n\n### 通信桥 (Bridges)\n\n通信桥 (bridge) 是一个组件和代理之间的通信通道。它允许组件向代理发送消息，并接收来自代理的消息。\n\n`use_bridge` 钩子也提供了在函数组件中创建桥梁的功能。\n\n### 派发器 (Dispatchers)\n\n派发器 (Dispatchers) 允许组件和代理之间进行单向通信，组件以此方式向代理发送消息。\n\n## 开销\n\n代理使用 Web Workers（即私有和公开）。它们在发送和接收消息时会产生序列化开销。代理使用 [bincode](https://github.com/bincode-org/bincode) 与其他线程通信，因此成本比仅调用函数要高得多。\n\n## 进一步阅读\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 示例展示了组件如何向代理发送消息并接收来自代理的消息。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: '使用 classes! 宏处理 CSS 类'\ndescription: '用一个方便的宏来处理 CSS 类'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew 并没有提供原生的 CSS-in-Rust 解决方案，但通过提供编程方式与 HTML `class` 属性交互的方式来辅助样式。\n\n## `classes!` 宏\n\n`classes!` 宏和相关的 `Classes` 结构简化了 HTML 类的使用：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n更多 CSS 相关的内容请参见[这个文档](../../more/css)。\n\n## 内联样式\n\n目前 Yew 并没有提供特殊的辅助工具来处理通过 `style` 属性指定的内联样式，但你可以像处理其他 HTML 属性一样处理它：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n更多 CSS 相关的内容请参见[这个文档](../../more/css)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: '使用 html! 宏处理 HTML'\ndescription: '这是 HTML，但不完全是！'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n你可以使用 `html!` 宏编写类似 HTML 的表达式。Yew 会在后台将其转换为表达 DOM 的 Rust 代码。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\n类似于格式化表达式，您可以通过使用花括号将周围上下文的值嵌入 HTML 中：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n使用 `html!` 有一个重要的规则 - 您只能返回一个包装节点。为了渲染多个元素的列表，`html!` 允许使用空标签（Fragments）。空标签是没有名称的标签，它们本身不会产生 HTML 元素。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// 错误：只允许一个根 HTML 元素\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修复：使用 HTML 空标签包裹\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n更多关于 Yew 和 HTML 的内容请参见[更多 HTML](concepts/html/introduction.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'Javascript 与 Rust'\ndescription: '在 Rust 中使用 JavaScript'\ncomment: '尽量保持文件简短和简单。它的目的是让读者更容易地了解 Yew 中的组件，而不是提供正确的 API 文档'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew 在一个地方集中了一个可重用的 UI 部分可能需要的所有内容 - rust 文件，同时也在必要时保持底层技术的可访问性。\n\n截至今天，WebAssembly 对于 DOM 交互还不完全支持。这意味着即使在 Yew 中，我们有时也依赖于调用 JavaScript。接下来是涉及的库的概述。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一个在 JavaScript 和 Rust 函数之间建立调用桥梁的库和工具。\n\n我们强烈建议您查看他们的[文档](https://wasm-bindgen.github.io/wasm-bindgen/)和我们的[快速指南](./wasm-bindgen.mdx)。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 为 Web API 提供了绑定，并允许我们以一种经过 Rust 处理和安全的方式编写 JavaScript 代码。\n\n示例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n再次强调，我们强烈建议您查看他们的[文档](https://wasm-bindgen.github.io/wasm-bindgen/)和我们的[快速指南](./web-sys.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一个在 JavaScript 和 Rust 函数之间建立调用桥梁的库和工具。它是由 [Rust 和 WebAssembly 工作组](https://rustwasm.github.io/) 使用 Rust 构建的。\n\nYew 使用 `wasm-bindgen` 通过一些 crate 与浏览器进行交互：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\n本节将从更抽象的层次上探讨这些 crate，以便更容易地理解和使用 Yew 中的 `wasm-bindgen` API。要了解有关 `wasm-bindgen` 及其相关 crate 的更深入指南，请查看 [`wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/)。\n\n有关上述 crate 的文档，请查看 [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html)。\n\n:::tip\n使用 `wasm-bindgen` doc.rs 搜索来查找已使用 `wasm-bindgen` 导入的浏览器 API 和 JavaScript 类型。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\n这个 crate 为上面的其他 crate 提供了许多构建块。在本节中，我们只会涵盖 `wasm-bindgen` crate 的两个主要领域，即宏和一些您会一遍又一遍看到的类型/特性。\n\n### `#[wasm_bindgen]` macro\n\n`#[wasm_bindgen]` 宏提供了 Rust 和 JavaScript 之间的接口，提供了一个在两者之间进行转换的系统。使用这个宏更为高级，除非您要使用外部 JavaScript 库，否则不应该使用它。`js-sys` 和 `web-sys` crate 为内置 JavaScript 类型和浏览器 API 提供了 `wasm-bindgen` 定义。\n\n让我们通过一个简单的示例来使用 `#[wasm-bindgen]` 宏来导入一些特定版本的 [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 函数。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// 首先让我们手动绑定 `console.log`，而不使用 `web_sys` 的帮助。\n// 在这里，我们手动编写 `#[wasm_bindgen]` 注解，我们程序的正确性取决于这些注解的正确性！\n#[wasm_bindgen]\nextern \"C\" {\n    // 在这里使用 `js_namespace` 来绑定 `console.log(..)` 而不是只有 `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` 是多态的，所以我们可以使用多个签名绑定它。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 多个参数也是可以的！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// 使用导入的函数！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_这个示例是基于 [1.2 使用 console.log 的 `wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) 改编的。_\n\n### 模拟继承\n\n在 JavaScript 类之间的继承是 JavaScript 语言的核心特性，DOM（文档对象模型）是围绕它设计的。当使用 `wasm-bindgen` 导入类型时，您还可以添加描述它们继承关系的属性。\n\n在 Rust 中，这种继承关系使用 [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) 和 [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) 特性来表示。这里举个例子可能会有所帮助；假设您有三种类型 `A`、`B` 和 `C`，其中 `C` 扩展了 `B`，而 `B` 又扩展了 `A`。\n\n在导入这些类型时，`#[wasm-bindgen]` 宏将按照以下方式实现 `Deref` 和 `AsRef` 特性：\n\n- `C` 可以 `Deref` 到 `B`\n- `B` 可以 `Deref` 到 `A`\n- `C` 可以被 `AsRef` 到 `B`\n- `C` 和 `B` 都可以被 `AsRef` 到 `A`\n\n这些实现允许您在 `C` 的实例上调用 `A` 的方法，并将 `C` 用作 `&B` 或 `&A`。\n\n需要注意的是，使用 `#[wasm-bindgen]` 导入的每种类型都有相同的根类型，您可以将其视为上面示例中的 `A`，这种类型是 [`JsValue`](#jsvalue)，下面有它的部分。\n\n_[`wasm-bindgen` 指引中的 extends 部分](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\n这是 JavaScript 拥有的对象的表示，这是 `wasm-bindgen` 的根捕获类型。任何来自 `wasm-bindgen` 的类型都是 `JsValue`，这是因为 JavaScript 没有强类型系统，因此接受变量 `x` 的任何函数都不定义其类型，因此 `x` 可以是有效的 JavaScript 值；因此 `JsValue`。如果您正在使用接受 `JsValue` 的导入函数或类型，那么任何导入的值在技术上都是有效的。\n\n`JsValue` 可以被函数接受，但该函数可能仍然只接受某些类型，这可能会导致 panic - 因此在使用原始 `wasm-bindgen` API 时，请检查导入的 JavaScript 的文档，以确定是否会在该值不是某种类型时引发异常（panic）。\n\n_[`JsValue` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)。_\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust 有一个强类型系统，而 JavaScript……没有😞。为了让 Rust 保持这些强类型但仍然方便，WebAssembly 工作组提出了一个非常巧妙的特性 `JsCast`。它的工作是帮助您从一个 JavaScript \"类型\" 转换到另一个 \"类型\"，这听起来很模糊，但它意味着如果您有一个类型，您知道它是另一个类型，那么您可以使用 `JsCast` 的函数从一个类型跳到另一个类型。当使用 `web-sys`、`wasm_bindgen`、`js-sys` 时，了解这个很好的特性 - 您会注意到许多类型将从这些 crate 中实现 `JsCast`。\n\n`JsCast` 提供了转换的检查和不检查方法 - 因此在运行时，如果您不确定某个对象是什么类型，您可以尝试将其转换，这将返回可能的失败类型，如 [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) 和 [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)。\n\n一个常见的例子是在 [`web-sys`](./web-sys.mdx) 中，当您尝试获取事件的目标时。您可能知道目标元素是什么，但 [`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API 总是会返回一个 [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)。\n您需要将其转换为元素类型，以便调用其方法。\n\n```rust\n// 需要先导入这个 Trait\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // 也许目标是一个选择元素？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 做点别的\n        return;\n    }\n\n    // 如果它能确定不是一个选择元素，那么我可以肯定它是一个输入元素！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) 方法是一个检查的转换，返回一个 `Option<&T>`，这意味着如果转换失败，则可以再次使用原始类型，因此返回 `None`。[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 方法将消耗 `self`，这是 Rust 中 `into` 方法的约定，返回的类型是 `Result<T, Self>`。如果转换失败，则原始的 `Self` 值将在 `Err` 中返回。您可以再试一次或对原始类型进行其他操作。\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 类型提供了一种将 Rust 闭包传递到 JavaScript 的方法，出于健全性原因，传递给 JavaScript 的闭包必须具有 `'static` 生命周期。\n\n这种类型是一个“句柄”，意味着每当它被丢弃时，它将使其引用的 JS 闭包无效。在 `Closure` 被丢弃后，对 JS 中闭包的任何使用都将引发异常。\n\n当您使用接受类型 [`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 的 `js-sys` 或 `web-sys` API 时，通常会使用 `Closure`。在 [Events](../html/events.mdx) 页面的 [Using `Closure` 部分](../html/events.mdx#using-closure-verbose) 中可以找到在 Yew 中使用 `Closure` 的示例。\n\n_[`Closure` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` crate 提供了 JavaScript 标准内置对象的绑定/导入，包括它们的方法和属性。\n\n这不包括任何 Web API，因为这是 [`web-sys`](./web-sys.mdx) 的作用！\n\n_[`js-sys` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` crate 提供了一个桥梁，用于将 JavaScript Promise 类型作为 Rust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 进行处理，并包含将 Rust Future 转换为 JavaScript Promise 的实用程序。当在 Rust（wasm）中处理异步或其他阻塞工作时，这可能很有用，并提供了与 JavaScript 事件和 JavaScript I/O 原语进行交互的能力。\n\n目前这个 crate 中有三个主要接口：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   一个使用 [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) 构造的类型，然后可以用作 `Future<Output=Result<JsValue, JsValue>>`。如果 `Promise` 被解析，这个 `Future` 将解析为 `Ok`，如果 `Promise` 被拒绝，则解析为 `Err`，分别包含 `Promise` 的解析或拒绝值。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   将 Rust `Future<Output=Result<JsValue, JsValue>>` 转换为 JavaScript `Promise`。未来的结果将转换为 JavaScript 中的已解析或已拒绝 `Promise`。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   在当前线程上生成一个 `Future<Output = ()>`。这是在 Rust 中运行 Future 的最佳方法，而不是将其发送到 JavaScript。\n\n_[`wasm-bindgen-futures` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` 将是 Yew 中 `wasm-bindgen-futures` crate 中最常用的部分，因为这有助于使用具有异步 API 的库。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // 控制台输出 \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew 还在某些 API 中添加了对 futures 的支持，最值得注意的是您可以创建一个接受 `async` 块的 `callback_future` - 这在内部使用了 `spawn_local`。\n\n_[`spawn_local` 文档](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys crate 为 Web API 提供绑定。'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 为 Web API 提供绑定。这是从浏览器 WebIDL 生成的，这就是为什么有些名称如此之长，有些类型如此模糊的原因。\n\n## `web-sys` 中的特性 (features)\n\n`web-sys` crate 中启用了所有特性可能会给 Wasm 应用程序增加很多冗余。为了解决这个问题，大多数类型都是通过启用 features 进行控制的，这样你只需要包含你的应用程序所需的类型。Yew 启用了 `web-sys` 的几个特性，并在其公共 API 中公开了一些类型。你通常需要自行将 `web-sys` 添加为依赖项。\n\n## `web-sys` 中的继承\n\n在[模拟继承](./wasm-bindgen.mdx#simulating-inheritance)部分，你可以了解到 Rust 通常提供了一种模拟 JavaScript 中继承的方法。这在 `web-sys` 中非常重要，因为了解一个类型上有哪些方法意味着了解它的继承。\n\n这一部分将查看一个特定的元素，并使用 Rust 调用 [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) 列出其继承，直到该值为 [`JsValue`](./wasm-bindgen.mdx#jsvalue)。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement 是 HTML 中的 <textarea>。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意我们现在已经从 web-sys 类型转移到内置的 JavaScript 类型，\n    // 这些类型在 js-sys crate 中。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意我们现在已经从 js-sys 类型转移到 wasm-bindgen crate 中的根 JsValue。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // 这样使用 deref 意味着我们必须手动遍历继承树。\n    // 但是，您可以在 HtmlTextAreaElement 类型上调用 JsValue 方法。\n    assert!(!text_area.is_string());\n\n    // 这个空函数只是为了证明我们可以将 HtmlTextAreaElement 作为 &EventTarget 传递。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // 编译器将沿着 deref 链向下走，以匹配这里的类型。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 实现允许您将 HtmlTextAreaElement 视为 &EventTarget。\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[`wasm-bindgen` 指引中的 `web-sys` 继承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)_\n\n## `NodeRef` 中的 `Node`\n\nYew 使用 [`NodeRef`](concepts/function-components/node-refs.mdx) 来提供一种方式来保留由 [`html!`](concepts/html/introduction.mdx) 宏创建的 `Node` 的引用。`NodeRef` 中的 `Node` 指的是 [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html)。`NodeRef::get` 方法将返回一个 `Option<Node>` 值，但是，在 Yew 中，大多数情况下，您希望将此值转换为特定元素，以便使用其特定方法。如果存在，可以使用 [`JsCast`](./wasm-bindgen.mdx#JsCast) 对 `Node` 值进行转换，但是 Yew 提供了 `NodeRef::cast` 方法来执行此转换，以方便使用，因此您不一定需要为 `JsCast` 特性包含 `wasm-bindgen` 依赖项。\n\n下面的两个代码块本质上是相同的，第一个使用 `NodeRef::cast`，第二个使用 [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 在 `NodeRef::get` 返回的 `web_sys::Node` 上。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // 在这里处理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // 在这里处理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript 重构为 Rust 的示例\n\n这一节展示了如何将与 Web API 交互的 JavaScript 代码示例重写为 Rust 中的 `web-sys`。\n\n### JavaScript 示例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e 为鼠标事件对象\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 元素内的 x 位置。\n    var y = e.clientY - rect.top // 元素内的 y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### 用 `web-sys` 重写的示例\n\n仅使用 `web-sys`，上面的 JavaScript 示例可以这样实现：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 需要启用所有我们想要使用的 web-sys 特性！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 我们现在需要保存 `mousemove` 闭包，以便在事件触发时闭包仍然在内存中。\n```\n\n这个版本更加冗长，但你可能会注意到其中的一部分是由于失败类型提醒我们，一些函数调用有必须保持的不变量，否则将在 Rust 中引发 panic。另一个冗长的部分是调用 `JsCast` 来将不同类型转换为特定类型，以便调用其特定方法。\n\n### 用 Yew 重写的示例\n\n在 Yew 中，您将主要创建 [`Callback`](concepts/function-components/callbacks.mdx) 以在 [`html!`](concepts/html/introduction.mdx) 宏中使用，因此示例将使用这种方法，而不是完全复制上面的方法：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# 我们需要启用 `DomRect` 特性以使用 `get_bounding_client_rect` 方法。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 补充依赖库\n\n`web-sys` 是 Web API 的原始绑定，因此在 Rust 中会有一些痛苦，因为它并不是为 Rust 或甚至强类型系统设计的，这就是社区 crate 提供了对 `web-sys` 的抽象，以提供更符合 Rust 习惯的 API。\n\n_[补充依赖库清单](/community/external-libs)_\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/contexts.mdx",
    "content": "---\ntitle: '上下文 (Contexts)'\nsidebar_label: Contexts\ndescription: '使用上下文传递深度嵌套数据'\n---\n\n通常，数据是通过 props 从父组件传递到子组件。\n但是，如果必须通过中间的许多组件传递它们，或者如果应用程序中的许多组件需要相同的信息，传递 props 可能会变得冗长和烦人。\n上下文解决了这个问题，允许父组件使数据可用于其下方树中的任何组件，无论多深，而无需通过 props 传递它们。\n\n## 使用 props 的问题：\"Prop Drilling\"\n\n传递 [props](./function-components/properties.mdx) 是从父组件直接传递数据到子组件的好方法。\n但是，当需要通过深层嵌套的组件树传递数据或多个组件共享相同的数据时，传递 props 变得繁琐。\n一种常见的数据共享解决方案是将数据提升到一个共同的祖先，并使子组件将其作为 props 接收。\n然而，这可能导致 props 必须通过多个组件才能到达需要它的组件。\n这种情况称为 \"Prop Drilling\"。\n\n考虑以下示例，它通过 props 传递主题：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App 根节点\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n我们通过 `Navbar` 传递主题设定，以便它可以到达 `Title` 和 `NavButton`。\n如果 `Title` 和 `NavButton` 这些需要访问主题的组件可以直接访问主题而不必通过 prop 传递，那就更好了。\n上下文解决了这个问题，允许父组件将数据（在这种情况下是主题）传递给其子组件。\n\n## 使用上下文\n\n### 步骤 1：提供上下文\n\n需要一个上下文提供者来消费上下文。`ContextProvider<T>`，其中 `T` 是用作提供者的上下文结构体。\n`T` 必须实现 `Clone` 和 `PartialEq`。`ContextProvider` 是其子组件将拥有上下文的组件。\n当上下文更改时，子组件会重新渲染。一个结构体用于定义要传递的数据。`ContextProvider` 可以这样使用：\n\n```rust\nuse yew::prelude::*;\n\n/// App 主题\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// 主组件\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` 是 `Rc<UseStateHandle<Theme>>` 类型，而我们需要 `Theme`\n        // 所以我们对它进行解引用。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // 这里的每个子组件及其子组件都将访问此上下文。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// 工具栏\n/// 此组件可以访问上下文。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// 放置在 `Toolbar` 中的按钮\n/// 由于此组件是组件树中 `ThemeContextProvider` 的子组件，它也可以访问上下文。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### 步骤 2：使用上下文\n\n#### 函数组件\n\n`use_context` 钩子用于在函数组件中使用上下文。\n请参阅 [use_context 文档](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) 了解更多信息。\n\n#### 结构体组件\n\n我们有两种选择在结构体组件中使用上下文：\n\n- [高阶组件](../advanced-topics/struct-components/hoc)：一个高阶函数组件将使用上下文并将数据传递给需要它的结构体组件。\n- 直接在结构体组件中使用上下文。请参阅 [结构体组件作为消费者的示例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## 使用场景\n\n通常，如果某些数据需要在树的不同部分的远程组件中使用，上下文可能会对你有所帮助。\n以下是一些这样的例子：\n\n- **主题**：你可以在应用程序的顶部放置一个上下文来保存你的应用程序主题，并使用它来调整视觉外观，如上例所示。\n- **当前用户帐户**：在许多情况下，组件需要知道当前登录的用户。你可以使用上下文将当前用户对象提供给组件。\n\n### 使用上下文前的考虑\n\n上下文非常容易使用，这也使得它们非常容易被误用/过度使用。\n仅仅因为你可以使用上下文将 props 共享给多个层级深的组件，并不意味着你应该这样做。\n\n例如，你可以提取一个组件并将该组件作为子组件传递给另一个组件。例如，\n你可能有一个 `Layout` 组件，它将 `articles` 作为 prop 并传递给 `ArticleList` 组件。\n你应该重构 `Layout` 组件，使其接受子组件作为 props 并显示 `<Layout> <ArticleList {articles} /> </Layout>`。\n\n## 修改子组件的上下文值\n\n由于 Rust 的所有权规则，上下文不能有一个可以被子组件调用的 `&mut self` 方法。\n要修改上下文的值，我们必须将其与 reducer 结合使用。这可以通过使用\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) 钩子来完成。\n\n[上下文示例](https://github.com/yewstack/yew/tree/master/examples/contexts) 演示了使用上下文的可变上下文\n\n## 进一步阅读\n\n- [上下文示例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: '回调 (Callbacks)'\n---\n\n回调函数用于在组件树中向上传递信息，以及在事件处理期间与其他组件（如代理或 DOM）进行通信。在内部，回调函数的类型只是一个 `Fn`，并且被包装在 `Rc` 中，以便它们可以被廉价地克隆。\n\n如果您想手动调用回调函数，可以使用 `emit` 函数。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // 调用回调函数\n// web_sys::console::log_1(&result.into()); // 如果取消注释，将打印 \"Bye Bob\"\n```\n\n## 将回调函数作为属性传递\n\n在 yew 中的一个常见模式是创建一个回调函数，并将其作为属性传递给子组件。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 然后提供属性 (Props)\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // 如果取消注释，这里会打印文本\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM 事件和回调函数\n\n回调函数也用于连接到 DOM 事件。\n\n例如，这里我们定义了一个回调函数，当用户点击按钮时将会调用：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // 如果取消注释，这里会打印文本\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子元素 (Children)'\n---\n\n`Children` 是一种特殊的属性类型，允许您接收嵌套的 `Html`，就像 html 子元素一样提供。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` 键很重要！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // 可以靠这种方式转发子元素\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/communication.mdx",
    "content": "---\ntitle: '组件之间的通信'\n---\n\n## 父组件向子组件发送消息\n\n将数据作为 [props](./properties) 传递，这会导致重新渲染，这是向子组件传递消息的方法。\n\n## 子组件向父组件发送消息\n\n通过 props 传递一个回调，子组件在事件上可以调用。[示例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/generics.mdx",
    "content": "---\ntitle: '泛型组件'\ndescription: '函数组件的 #[component] 属性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 属性也适用于用于创建泛型组件的泛型函数。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// 之后可以像这样使用\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// 或者\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: '自定义 Hooks'\n---\n\n## 定义自定义 Hooks\n\n组件的有状态逻辑可以通过创建自定义 Hooks 来提取为可重用的函数。\n\n假设我们希望创建一个事件监听器，监听 `window` 对象上的事件。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\n这段代码有一个问题：逻辑无法被另一个组件重用。如果我们构建另一个监听不同事件的组件，而不是复制代码，我们可以将逻辑移入自定义 hook。\n\n我们将首先创建一个名为 `use_event` 的新函数。`use_` 前缀表示函数是一个 hook。此函数将接受一个事件目标、一个事件类型和一个回调。所有 hook 必须在其函数定义上标记为 `#[hook]`。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\n这个简单的 hook 可以通过组合内置 hook 创建。在本例中，我们将使用 `use_effect_with` hook，因此当 hook 参数发生变化时，可以重新创建事件监听器。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\n尽管这种方法在几乎所有情况下都有效，但它无法用于编写像我们已经使用的预定义 hook 那样的基本 hook。\n\n查看 [docs.rs](https://docs.rs/yew) 上的文档以及 `hooks` 目录，查看预定义 hook 的实现。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks 是一类能够存储状态和执行副作用的函数。\n\nYew 提供了一些预定义的 hooks。您也可以创建自己的 hooks，或者发现许多[社区制作的 hooks](/community/awesome#hooks)。\n\n## Hooks 规则\n\n1. 每个 Hook 函数的名称必须以 `use_` 开头\n2. Hooks 只能在以下位置使用：\n    - 函数/ Hook 的顶层\n    - 函数/ Hook 内的块，只要它没有被分支\n    - 函数/ Hook 内顶层 `if` 表达式的条件\n    - 函数/ Hook 内顶层 `match` 表达式的选择器\n3. 每次渲染时，Hooks 必须以相同的顺序调用。只有在使用 [Suspense](../../suspense.mdx) 时才允许提前返回\n\n这些规则由编译时或运行时错误来执行。\n\n### 预定义 Hooks\n\nYew 提供了以下预定义 Hooks：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\n这些 hooks 的文档可以在 [Yew API 文档](https://yew-rs-api.web.app/next/yew/functional/)中找到。\n\n### 自定义 Hooks\n\n有些情况下，您可能希望定义自己的 Hooks，以将组件中的可能具有状态的逻辑封装到可重用的函数中。\n\n## 进一步阅读\n\n- React 文档中有一个关于 [React hooks](https://reactjs.org/docs/hooks-intro.html) 的部分。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函数组件'\nslug: /concepts/function-components\n---\n\n让我们重新回顾一下之前的标语：\n\n> Yew 的核心思想是将可重用的 UI 部分所需的所有内容集中在一个地方 - Rust 文件中。\n\n我们将通过引入将定义应用程序的逻辑和呈现行为的概念来完善这个陈述：\"组件\"。\n\n## 什么是组件？\n\n组件是 Yew 的构建块。\n\n它们应当：\n\n- 以 [Props](./properties.mdx) 的形式接受参数\n- 可以拥有自己的状态\n- 计算用户可见的 HTML 片段（DOM）\n\n## Yew 组件的两种风味\n\n您当前正在阅读有关函数组件的内容 - 这是在开始使用 Yew 时以及在编写简单的呈现逻辑时编写组件的推荐方式。\n\n还有一种更高级但不太容易访问的编写组件的方式 - [结构组件](advanced-topics/struct-components/introduction.mdx)。它们允许非常详细的控制，尽管大多数情况下您不需要那么详细的控制。\n\n## 创建函数组件\n\n要创建一个函数组件，请将 `#[component]` 属性添加到一个函数中。按照惯例，函数的名称采用 PascalCase，与 `html!` 宏中的普通 html 元素形成对比。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 然后在其他地方，您可以在 `html!` 中使用组件\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## 组件内部发生了什么\n\n在渲染时，Yew 将构建这些组件的虚拟树。它将调用每个（函数）组件的 view 函数来计算 DOM 的虚拟版本（VDOM），您作为库用户将其视为 `Html` 类型。对于上面的示例，这将如下所示：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n当需要更新时，Yew 将再次调用 view 函数，并将新的虚拟 DOM 与其之前的版本进行协调，并仅将新的/更改的/必要的部分传 播到实际的 DOM。这就是我们所说的 **渲染**。\n\n:::note\n\n实际上，`Html` 只是 `VNode` 的别名 - 一个虚拟节点。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: '节点引用'\ndescription: 'DOM 外部访问'\n---\n\n`ref` 属性可以用于将 `NodeRef` 附加到 HTML 元素上。在回调中，您可以获取 `ref` 附加到的 DOM `Element`。这可以用于在 `view` 生命周期方法之外对 DOM 进行更改，检索 `<input>` 的值以及通过 javascript API 直接与 DOM 交互。\n\n这对于获取 canvas 元素或滚动到页面的不同部分很有用。\n\n:::caution\n不要手动修改 Yew 渲染的 DOM 树。如果不确定，请将 `NodeRef` 视为只读访问。\n:::\n\n## 进一步阅读\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` 示例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '属性 (Properties)'\ndescription: '父子组件通信'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n属性 (Properties) 通常被简写为 \"Props\"。\n\n:::\n\n属性 (Properties) 是组件的参数，Yew 可以监视这些参数。\n\n在组件的属性中使用一个类型之前，它必须实现 `Properties` trait。\n\n## 响应性\n\n在重新渲染时，Yew 在协调虚拟 DOM 时检查属性是否已更改，以了解是否需要重新渲染嵌套组件。这样，Yew 可以被认为是一个非常具有响应性的框架，因为来自父组件的更改总是会向下传播，视图永远不会与来自属性/状态的数据不同步。\n\n:::tip\n\n如果您尚未完成 [教程](../../tutorial)，请尝试并自行测试这种响应性！\n\n:::\n\n## 派生宏\n\nYew 提供了一个派生宏，可以轻松地在结构体上实现 `Properties` trait。\n\n您派生 `Properties` 的类型也必须实现 `PartialEq`，以便 Yew 可以进行数据比较。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函数组件中使用\n\n属性 `#[component]` 允许在函数参数中选择性地接收 Props。要提供它们，可以通过 `html!` 宏中的属性进行赋值。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// 然后提供属性\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 没有属性需要提供\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生宏字段属性\n\n在派生 `Properties` 时，默认情况下所有字段都是必需的。\n\n以下属性允许您为属性提供默认值，当父组件没有设置它们时将使用这些默认值。\n\n:::tip\n属性在 Rustdoc 生成的文档中是不可见的。您的属性的文档字符串应该提到一个属性是否是可选的，以及它是否有一个特殊的默认值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` trait 的字段类型的默认值初始化属性值。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 这样使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 来初始化属性值。`value` 可以是返回字段类型的任何表达式。\n\n例如，要将布尔属性默认为 `true`，请使用属性 `#[prop_or(true)]`。当属性被构造时，表达式会被评估，且没有给出明确的值。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// 这样使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n调用 `function` 来初始化属性值。`function` 应该具有 `FnMut() -> T` 签名，其中 `T` 是字段类型。当没有为该属性给出明确的值时，将调用该函数。\n这个函数在属性被构造时被调用。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// 使用默认值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或者不覆盖默认值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的性能开销\n\n内部属性是以引用计数的智能指针传递的。这意味着只有一个共享指针被传递到组件树中的属性，这样就能节约克隆整个属性的高昂成本。\n\n:::tip\n`AttrValue` 是我们用于属性值的自定义类型，这样就不用将它们定义为 String 或其他类似克隆成本高昂的类型了。\n:::\n\n## Props 宏\n\n`yew::props!` 宏允许您以与 `html!` 宏相同的方式构建属性。\n\n该宏使用与结构表达式相同的语法，只是您不能使用属性或基本表达式 (`Foo { ..base }`)。类型路径可以直接指向属性 (`path::to::Props`)，也可以指向组件的关联属性 (`MyComp::Properties`)。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 注意我们不需要指定 name 属性\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自动生成属性 (yew-autoprops)\n\n为了简化您的开发流程，您还可以使用宏 `#[autoprops]`（来自 `yew-autoprops` 包）自动生成 `Properties` 结构体。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] 宏必须出现在 #[component] 之前，顺序很重要\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 结构体 \"GreetingsProps\" 将会被自动生成。\n//\n// `is_loading` 将作为值传递给组件，而 `message` 和 `name` 将使用引用，因为定义中有一个前导的 `&`。\n```\n\n## 评估顺序\n\n属性按照指定的顺序进行评估，如下例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n虽然几乎任何 Rust 类型都可以作为属性传递，但有一些反模式应该避免。这些包括但不限于：\n\n1. 使用 `String` 类型而不是 `AttrValue`。 <br />\n   **为什么不好？** `String` 克隆成本高昂。当属性值与钩子和回调一起使用时，通常需要克隆。`AttrValue` 是一个引用计数的字符串 (`Rc<str>`) 或一个 `&'static str`，因此非常便宜克隆。<br />\n   **注意**：`AttrValue` 在内部是来自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看该包以了解更多信息。\n2. 使用内部可变性。 <br />\n   **为什么不好？** 内部可变性（例如 `RefCell`、`Mutex` 等）应该 _通常_ 避免使用。它可能会导致重新渲染问题（Yew 不知道状态何时发生了变化），因此您可能需要手动强制重新渲染。就像所有事物一样，它有其用武之地。请谨慎使用。\n3. 使用 `Vec<T>` 类型而不是 `IArray<T>`。 <br />\n   **为什么不好？** `Vec<T>`，就像 `String` 一样，克隆成本也很高。`IArray<T>` 是一个引用计数的切片 (`Rc<[T]>`) 或一个 `&'static [T]`，因此非常便宜克隆。<br />\n   **注意**：`IArray` 可以从 [implicit-clone](https://crates.io/crates/implicit-clone) 导入。查看该包以了解更多信息。\n4. 您发觉可能的新内容。您是否遇到了一个希望早点了解清楚的边缘情况？请随时创建一个问题或向本文档提供修复的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一个实验性包，允许您根据函数的参数动态创建 Props 结构体。如果属性结构体永远不会被重用，这可能会很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '纯组件'\n---\n\n每个函数组件都是一个[纯](https://zh.wikipedia.org/wiki/%E7%BA%AF%E5%87%BD%E6%95%B0)函数，它接受一个属性对象并返回一个 `Html` 对象。纯函数是指在给定相同输入时，总是返回相同输出的函数。\n\n这个例子是一个纯组件。对于给定的属性 `is_loading`，它总是返回相同的 `Html`，没有任何副作用。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n如果您有一个内部纯组件，它不使用 hooks 和其他组件机制，您通常可以将其编写为返回 `Html` 的普通函数，从而避免 Yew 运行组件生命周期相关的一些开销。使用 [表达式语法](concepts/html/literals-and-expressions.mdx#expressions) 在 `html!` 中渲染它们。\n:::\n\n## 非纯组件\n\n您可能想知道，如果组件不使用任何全局变量，那么它是否可以是不“纯”的，因为它只是在每次渲染时调用的固定函数。\n这就是下一个主题 - [hooks](./hooks) 的用武之地。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/state.mdx",
    "content": "---\ntitle: '状态'\n---\n\n## 如何存储状态的一般视图\n\n这个表格可以作为一个指南，帮助您决定哪种状态存储类型最适合您的用例：\n\n| Hook             | 类型                       | 何时渲染?                        | 作用域                   |\n| ---------------- | -------------------------- | -------------------------------- | ------------------------ |\n| [use_state]      | `T`                        | 被设置一个值                     | 组件内部实例             |\n| [use_state_eq]   | `T: PartialEq`             | 被设置一个不同的值               | 组件内部实例             |\n| [use_reducer]    | `T: Reducible`             | 被调用归纳                       | 组件内部实例             |\n| [use_reducer_eq] | `T: Reducible + PartialEq` | 被调用归纳，归纳后的值与之前不同 | 组件内部实例             |\n| [use_memo]       | `Deps -> T`                | 依赖项发生变化                   | 组件内部实例             |\n| [use_callback]   | `Deps -> Callback<E>`      | 依赖项发生变化                   | 组件内部实例             |\n| [use_mut_ref]    | `T`                        | -                                | 组件内部实例             |\n| 全局静态常量     | `T`                        | -                                | 全局，任何位置都可以使用 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/classes.mdx",
    "content": "---\ntitle: '类'\ndescription: '一个方便的宏来处理类'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 类\n\n`Classes` 结构体可以用来处理 HTML 类。\n\n将字符串推送到集合时，`Classes` 确保每个类都有一个元素，即使单个字符串可能包含多个类。\n\n`Classes` 也可以通过使用 `Extend`（即 `classes1.extend(classes2)`）或 `push()`（即 `classes1.push(classes2)`）来合并。任何实现 `Into<Classes>` 的类型都可以推送到现有的 `Classes` 上。\n\n`classes!` 是一个方便的宏，它创建一个单一的 `Classes`。它的输入接受一个逗号分隔的表达式列表。唯一的要求是每个表达式都实现了 `Into<Classes>`。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 接受类的组件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/components.mdx",
    "content": "---\ntitle: '组件'\ndescription: '使用组件层次结构创建复杂的布局'\n---\n\n## 基础\n\n组件可以在 `html!` 宏中使用：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // 没有属性\n        <MyComponent />\n\n        // 使用属性\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // 一次性提供所有属性\n        <MyComponentWithProps ..props.clone() />\n\n        // 使用变量中的属性，并覆盖特定值\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## 嵌套\n\n如果组件在其 `Properties` 中有一个 `children` 字段，它可以接受子组件/元素\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` 宏允许您使用 `..props` 语法传递一个基本表达式，而不是单独指定每个属性，类似于 Rust 的[函数式更新语法](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax)。\n这个基本表达式必须出现在传递任何单独的 props 之后。\n当传递一个带有 `children` 字段的基本 props 表达式时，`html!` 宏中传递的子元素将覆盖已经存在于 props 中的子元素。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子元素将覆盖 props.children\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 相关示例\n\n- [函数化 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [函数化路由](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '条件渲染'\ndescription: '在 html 中有条件地渲染节点！'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If 块\n\n要有条件地渲染一些标记，我们将其包装在 `if` 块中：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/elements.mdx",
    "content": "---\ntitle: '元素'\ndescription: '支持 HTML 和 SVG 元素'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM 节点\n\n在 Yew 中手动创建或管理 DOM 节点的原因有很多，比如与可能与受管理组件冲突的 JS 库集成。\n\n使用 `web-sys`，您可以创建 DOM 元素并将其转换为 `Node` - 然后可以使用 `VRef` 将其用作 `Html` 值：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // 带记忆能力的函数，只会执行一次\n    let node = use_memo(\n        (),\n        |_| {\n            // 从文档中创建一个 div 元素\n            let div: Element = document().create_element(\"div\").unwrap();\n            // 添加内容、类等\n            div.set_inner_html(\"Hello, World!\");\n            // 将 Element 转换为 Node\n            let node: Node = div.into();\n            // 将该 Node 作为 Html 值返回\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo 返回的是 Rc 指针，所以我们需要解引用和克隆\n    (*node).clone()\n}\n\n```\n\n## 动态标签名\n\n在构建高阶组件时，您可能会发现自己处于一个标签名不是静态的情况。例如，您可能有一个 `Title` 组件，根据级别属性可以渲染从 `h1` 到 `h6` 的任何内容。而不是使用一个大的匹配表达式，Yew 允许您动态设置标签名，使用 `@{name}`，其中 `name` 可以是返回字符串的任何表达式。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 逻辑值属性\n\n一些内容属性（例如 checked、hidden、required）被称为逻辑值属性。在 Yew 中，逻辑值属性需要设置为布尔值：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\n这与以下的 **HTML** 功能上是等价的：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n将逻辑值属性设置为 false 等效于不使用该属性；可以使用逻辑表达式的值：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\n这与以下 **HTML** 结果等价：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 类似字符串的属性\n\n除了一些逻辑值属性，您可能会处理很多类似字符串的 HTML 属性，Yew 有几种选项可以将类似字符串的值传递给组件。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\n它们都是有效的，**但**我们鼓励您更倾向于使用 Yew 的自定义 `AttrValue`，特别是如果您需要克隆或将它们作为属性传递给另一个组件。\n\n## HTML 元素的可选属性\n\n大多数 HTML 属性可以使用可选值（Some(x) 或 None）。这使我们可以在属性被标记为可选时省略该属性。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n如果属性设置为 `None`，则该属性将不会在 DOM 中设置。\n\n## 相关示例\n\n- [内嵌 HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/events.mdx",
    "content": "---\ntitle: '事件'\n---\n\n## 介绍\n\nYew 与 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate 集成，并使用该 crate 中的事件。下面的[表格](#event-types)列出了在 `html!` 宏中接受的所有 `web-sys` 事件。\n\n您仍然可以为下表中未列出的事件添加 [`Callback`](../function-components/callbacks.mdx)，请参见[手动事件监听器](#manual-event-listener)。\n\n## 事件类型\n\n:::tip\n所有的事件类型都在 `yew::events` 下重新导出。\n使用 `yew::events` 中的类型比手动将 `web-sys` 作为依赖项包含在您的 crate 中更容易确保版本兼容性，\n因为您不会使用与 Yew 指定的版本冲突的版本。\n:::\n\n事件监听器的名称是在 `html` 宏中添加事件 `Callback` 时预期的名称：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\n事件名称是监听器名称去掉 \"on\" 前缀，因此 `onclick` 事件监听器监听 `click` 事件。查看本页末尾的[完整事件列表](#available-events)及其类型。\n\n## 事件捕获 {#event-bubbling}\n\nYew 调度的事件遵循虚拟 DOM 层次结构，向上冒泡到监听器。目前，仅支持监听器的冒泡阶段。请注意，虚拟 DOM 层次结构通常（但并非总是）与实际 DOM 层次结构相同。在处理[传送门](../../advanced-topics/portals)和其他更高级技术时，这一区别很重要。对于良好实现的组件，直觉应该是事件从子组件冒泡到父组件。这样，您在 `html!` 中编写的层次结构就是事件处理程序观察到的层次结构。\n\n如果您不想要事件冒泡，可以通过调用\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n在启动应用程序*之前*。这会加快事件处理速度，但某些组件可能会因未收到预期的事件而中断。请谨慎使用！\n\n## 事件委托\n\n可能会让人惊讶的是，事件监听器并不是直接注册在它们被渲染的元素上。相反，事件是从 Yew 应用的子树根节点委托的。不过，事件仍然以其原生形式传递，并且不会创建任何合成形式。这可能会导致 HTML 监听器中预期的事件与 Yew 中出现的事件之间的不匹配。\n\n- [`Event::current_target`] 指向 Yew 子树根节点，而不是添加监听器的元素。如果您想访问底层的 `HtmlElement`，请使用 [`NodeRef`](../function-components/node-refs.mdx)。\n- [`Event::event_phase`] 始终是 [`Event::CAPTURING_PHASE`]。在内部，事件将表现得像是在冒泡阶段，事件传播将被重放，并且事件会[向上冒泡](#event-bubbling)，即虚拟 DOM 中较高的事件监听器将在较低的事件监听器之后触发。目前，Yew 不支持捕获监听器。\n\n这也意味着由 Yew 注册的事件通常会在其他事件监听器之前触发。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 具备类型的事件目标\n\n:::caution\n在本节中，**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** 始终指的是事件从其派发的元素。\n\n这**不一定**总是指代 `Callback` 所放置的元素。\n:::\n\n在事件 `Callback` 中，您可能希望获取该事件的目标。例如，`change` 事件没有提供任何信息，但用于通知某些内容已更改。\n\n在 Yew 中，以正确的类型获取目标元素可以通过几种方式完成，我们将在这里逐一介绍。调用事件上的 [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) 返回一个可选的 [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 类型，当您想知道输入元素的值时，这可能看起来不是很有用。\n\n在下面的所有方法中，我们将解决相同的问题，以便清楚地了解方法的不同之处，而不是手头的问题。\n\n**问题：**\n\n我们在 `<input>` 元素上有一个 `onchange` `Callback`，每次调用时，我们希望向组件发送一个[更新](components#update) `Msg`。\n\n我们的 `Msg` 枚举如下所示：\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### 使用 `JsCast`\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate 有一个有用的 trait：[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)，它允许我们在类型之间直接转换，只要它实现了 `JsCast` 就行。我们可以谨慎地转换，这涉及运行时检查和处理 `Option` 和 `Result` 的逻辑，或者我们也可以冒险直接强行转换。\n\n多说无益，看代码：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# 需要 wasm-bindgen 用于调用 JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // 当事件被创建时，目标是未定义的，只有在派发时才会添加目标。\n            let target: Option<EventTarget> = e.target();\n            // 事件可能会冒泡，因此此侦听器可能会捕获不是 HtmlInputElement 类型的子元素的事件。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // 你必须了解 target 是 HtmlInputElement，否则调用 value 将是未定义行为（UB）。\n        // 在这里，我们确信这是输入元素，因此我们可以在不检查的情况下将其转换为适当的类型。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` 提供的方法是 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\n和 [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)。\n如你所见，它们允许我们从 `EventTarget` 转换为 [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html)。\n`dyn_into` 方法是谨慎的，因为它会在运行时检查类型是否实际为 `HtmlInputElement`，如果不是则返回\n`Err(JsValue)`。[`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n是一个通用类型，将原来的对象返回给你，以便再次尝试转换为别的类型。\n\n这会儿你可能会想，什么时候可以使用危险版本？在上面的情况下，它是安全的<sup>1</sup>，因为我们将 `Callback` 设置在一个没有子元素的元素上，所以目标只能是同一个元素。\n\n_<sup>1</sup> 只要涉及到 JS 领域，就是安全的。_\n\n### 使用 `TargetCast`\n\n**强烈建议先阅读 [使用 JsCast](#using-jscast)！**\n\n:::note\n`TargetCast` 的设计目的是让新用户了解 `JsCast` 的行为，但范围更小，仅涉及事件及其目标。\n\n选用 `TargetCast` 或 `JsCast` 纯粹是个人偏好，实际您会发现 `TargetCast` 的实现和 `JsCast` 的功能很相似。\n:::\n\n`TargetCast` trait 是在 `JsCast` 基础之上构建的，专门用于从事件中获取类型化的事件目标。\n\n`TargetCast` 是 Yew 的一部分，因此无需添加依赖项即可在事件上使用 trait 方法，但它的工作方式与 `JsCast` 非常相似。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // 你必须清楚 target 是 HtmlInputElement，否则调用 value 将是未定义行为（UB）。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n如果您已经了解了 `JsCast`，或者了解了这个 trait，您可能会发现 `TargetCast::target_dyn_into` 与 `JsCast::dyn_into` 相似，但专门用于事件的目标。`TargetCast::target_unchecked_into` 与 `JsCast::unchecked_into` 类似，因此上面关于 `JsCast` 的所有警告都适用于 `TargetCast`。\n\n### 使用 `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) 可以代替查询给定给 `Callback` 的事件。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n通过 `NodeRef`，你可以忽略事件并使用 `NodeRef::cast` 方法获取一个 `Option<HtmlInputElement>` - 这是可选的，因为在设置 `NodeRef` 之前调用 `cast`，或者类型不匹配时将返回 `None`。\n\n你可能会看到，通过使用 `NodeRef`，我们不必将 `String` 发送回状态，因为我们总是访问 `input_node_ref` - 因此我们可以这样做：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // 对 value 做点什么\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\n您选择哪种方法取决于您的组件和您的偏好，没有所谓的*推荐*方法。\n\n## 手动事件监听器\n\n您可能希望监听 Yew 的 `html` 宏不支持的事件，查看[这里列出的支持的事件](#event-types)。\n\n为了手动向某个元素添加事件监听器，我们需要借助 [`NodeRef`](../function-components/node-refs.mdx)，以便在 `use_effect_with` 中使用 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) 和 [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API 添加监听器。\n\n以下示例将展示如何为虚构的 `custard` 事件添加监听器。所有不受 yew 支持的事件或自定义事件都可以表示为\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html)。如果您需要访问自定义/不受支持事件的特定方法或字段，可以使用\n[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) 的方法将其转换为所需的类型。\n\n### 使用 `Closure`（冗长版本）\n\n直接使用 `web-sys` 和 `wasm-bindgen` 的接口可能有点痛苦……所以要有点心理准备（[感谢 `gloo`，有了更简洁的方法](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 创建您通常会创建的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 对 custard 做点什么..\n                    });\n\n                    // 从 Box<dyn Fn> 创建一个 Closure - 这必须是 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有关 `Closure` 的更多信息，请参见 [wasm-bindgen 指南](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html)。\n\n### 使用 `gloo`（简洁版本）\n\n更方便的方法是使用 `gloo`，更具体地说是 [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)，\n它是 `web-sys`、`wasm-bindgen` 的高层抽象实现。\n\n`gloo_events` 提供了 `EventListener` 类型，可以用于创建和存储事件监听器。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 创建您通常会创建的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 对 custard 做点什么..\n                    });\n\n                    // 从 Box<dyn Fn> 创建一个 Closure - 这必须是 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有关 `EventListener` 的更多信息，请参见 [gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html)。\n\n## 可用事件的完整列表 {#available-events}\n\n| 侦听器名称                  | `web_sys` 事件类型                                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空标签 (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 宏总是需要一个根节点。为了绕过这个限制，您可以使用一个“空标签”（也称为“fragments”）。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// 错误：只允许一个根 HTML 元素\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: '用于生成 HTML 和 SVG 的过程宏'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 宏允许您声明性地编写 HTML 和 SVG 代码。它类似于 JSX（一种允许您在 JavaScript 中编写类似 HTML 的代码的扩展）。\n\n**重要提示**\n\n1. `html! {}` 宏只能接受一个根 HTML 节点（您可以通过使用 [fragments](./fragments.mdx) 或 [iterators](./../html/lists.mdx) 来规避这一点）\n2. 空的 `html! {}` 调用是有效的，不会渲染任何内容\n3. 字面量必须始终用引号引起来并用大括号括起来：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` 宏会将所有标签名称转换为小写。要使用大写字符（某些 SVG 元素所需的字符）请使用[动态标签名称](concepts/html/elements.mdx#dynamic-tag-names)：`html! { <@{\"myTag\"}></@> }`\n\n:::note\n`html!` 宏可能会达到编译器的默认递归限制。如果遇到编译错误，请在 crate 根目录添加类似 `#![recursion_limit=\"1024\"]` 的属性以解决问题。\n:::\n\n## 标签 (Tags) 结构\n\n标签 (Tags) 基于 HTML 标签。组件、元素和列表都基于此标签语法。\n\n标签必须要么自闭合 `<... />`，要么对于每个开始标签都有一个相应的结束标签。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 缺少闭合标签\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 缺少闭合标签\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n方便起见，通常需要闭合标签的元素**允许**自闭合。例如，编写 `html! { <div class=\"placeholder\" /> }` 是有效的。\n:::\n\n创建复杂的嵌套 HTML 和 SVG 布局还是很容易的：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\n如果您使用 Rust 编译器的开发者版本编译 Yew，宏将警告您可能遇到的一些常见陷阱。当然，您可能需要使用稳定版编译器（例如，您的组织可能有政策要求这样做）进行发布构建，但即使您使用的是稳定工具链，运行 `cargo +nightly check` 也可能会标记一些可以改进 HTML 代码的方法。\n\n目前，这些 lint 主要与可访问性相关。如果您有 lint 的想法，请随时[在此问题中发表意见](https://github.com/yewstack/yew/issues/1334)。\n\n## 指定属性和属性\n\n属性与普通 HTML 中的元素设置方式相同：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n属性在元素名称之前用 `~` 指定：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n如果值是一个字面量的话，围绕值的大括号可以省略。\n\n:::\n\n:::note 什么是字面量\n\n字面量是 Rust 中所有有效的[字面量表达式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)。请注意，[负数**不是**字面量](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)，因此必须用大括号括起来 `{-6}`。\n\n:::\n\n:::note 组件属性\n组件属性作为 Rust 对象传递，与此处描述的元素参数 (Attributes) / 属性 (Properties) 不同。\n在[组件属性](../function-components/properties.mdx)中了解更多信息。\n:::\n\n### 特殊属性\n\n有一些特殊属性不直接影响 DOM，而是作为 Yew 虚拟 DOM 的指令。目前有两个这样的特殊属性：`ref` 和 `key`。\n\n`ref` 允许您直接访问和操作底层 DOM 节点。有关更多详细信息，请参阅[Refs](../function-components/node-refs.mdx)。\n\n另一方面，`key` 为元素提供了一个唯一标识符，Yew 可以用于优化目的。\n\n:::info\n[了解更多相关内容](./html/lists)\n:::\n\n## 条件渲染\n\n可以通过使用 Rust 的条件结构来条件性地渲染标记。目前只支持 `if` 和 `if let`。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n阅读[条件渲染](./conditional-rendering.mdx)一节了解更多\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/lists.mdx",
    "content": "---\ntitle: '列表'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 迭代器\n\n从迭代器构建 HTML 有 3 种方法：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` 循环\">\n主要方法是使用 for 循环，与 Rust 中已有的 for 循环相同，但有 2 个关键区别：\n1. 与标准 for 循环不能返回任何内容不同，`html!` 中的 for 循环会被转换为节点列表；\n2. 发散表达式，即 `break`、`continue` 在 `html!` 中的 for 循环体内是不允许的。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` 块\">\n另一种方法是使用 `for` 关键字，这不是原生的 Rust 语法，而是由 HTML 宏用于输出显示迭代器所需的代码。\n当迭代器已经计算好，只需要将其传递给宏时，这种方法比第一种更好。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` 方法\">\n\n最后一种方法是在迭代器的最终转换上调用 `collect::<Html>()`，它返回一个 Yew 可以显示的列表。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 键 (Key) 列表\n\n键 (Key) 列表是一个优化的列表，其中**所有**子元素都有键。\n`key` 是 Yew 提供的一个特殊属性，它为 HTML 元素或组件提供一个唯一标识符，用于 Yew 内部的优化。\n\n:::caution\nKey 只需要在每个列表中是唯一的，与 HTML `id` 的全局唯一性相反。它不应该依赖于列表的顺序。\n:::\n\n始终建议为列表添加键 (key)。\n\n可以通过将唯一的 `String`、`str` 或整数传递给特殊的 `key` 属性来添加键：\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### 性能优化\n\n我们有一个[带有键 (keys) 的列表示例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)可以让你测试性能上的改进，这里是一个简单的测试流程：\n\n1. 进入[在线演示](https://examples.yew.rs/keyed_list)\n2. 添加 500 个元素\n3. 禁用键\n4. 反转列表\n5. 查看 \"最后一次渲染花费了 Xms\"（在撰写本文时，大约为 60ms）\n6. 启用键\n7. 再次反转列表\n8. 查看 \"最后一次渲染花费了 Xms\"（在撰写本文时，大约为 30ms）\n\n截至撰写本文时，对于 500 个组件，速度提高了 2 倍。\n\n### 原理解释\n\n通常，当你迭代时，只需要在每个列表项上添加一个键，数据的顺序可能会发生变化。\n在重新渲染列表时，它用于加速协调过程。\n\n如果没有键，假设你迭代 `[\"bob\", \"sam\", \"rob\"]`，最终得到的 HTML 如下：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n然后在下一次渲染时，如果你的列表更改为 `[\"bob\", \"rob\"]`，Yew 可以删除 id=\"rob\" 的元素，并将 id=\"sam\" 更新为 id=\"rob\"。\n\n如果你为每个元素添加了一个键，初始 HTML 将保持不变，但在使用修改后的列表 `[\"bob\", \"rob\"]` 进行渲染后，Yew 只会删除第二个 HTML 元素，而其他元素则保持不变，因为它可以使用键将它们关联起来。\n\n如果你遇到了一个从一个组件切换到另一个组件的 bug/\"feature\"，但两者都有一个 div 作为最高渲染元素。\nYew 在这些情况下会重用已渲染的 HTML div 作为优化。\n如果你需要该 div 被重新创建而不是被重用，那么你可以添加不同的键，它们将不会被重用。\n\n## 进一步阅读\n\n- [TodoMVC 示例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [带有键 (keys) 的列表示例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [路由示例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: '字面量和表达式'\n---\n\n## 字面量\n\n如果表达式解析为实现了 `Display` 的类型，它们将被转换为字符串并插入到 DOM 中作为 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 节点。\n\n:::note\n字符串字面量创建 `Text` 节点，浏览器将其视为字符串。因此，即使表达式包含 `<script>` 标签，您也不会遇到 XSS 等安全问题，除非您将表达式包装在 `<script>` 块中。\n:::\n\n所有显示文本都必须用 `{}` 块括起来，因为文本被视为表达式。这是 Yew 与普通 HTML 语法最大的偏差。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 表达式\n\n您可以使用 `{}` 块在 HTML 中插入表达式，只要它们解析为 `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常将这些表达式提取到函数或闭包中以优化可读性是有意义的：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/router.mdx",
    "content": "---\ntitle: '路由 (Router)'\ndescription: 'Yew 的官方路由库'\n---\n\n单页应用程序 (SPA) 中的路由器处理根据 URL 显示不同的页面。与点击链接时请求不同的远程资源的默认行为不同，路由器会在本地设置 URL 以指向应用程序中的有效路由。然后，路由器检测到此更改并决定要渲染的内容。\n\nYew 在 `yew-router` crate 中提供了路由器支持。要开始使用它，请将依赖项添加到您的 `Cargo.toml` 文件中。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n所需的工具均在 `yew_router::prelude` 模块中提供，\n\n## 用法\n\n最开始，你需要定义一个 `Route`。\n\n路由由一个 `enum` 定义，它派生自 `Routable`。这个枚举必须实现 `Clone + PartialEq`。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` 与 `<Switch />` 组件配对，后者会找到与浏览器当前 URL 匹配的路径变体，并将其传递给 `render` 回调。然后回调决定要渲染的内容。如果没有路径匹配，路由器会导航到带有 `not_found` 属性的路径。如果没有指定路由，则不会渲染任何内容，并且会在控制台中记录一条消息，说明没有匹配的路由。\n\nyew-router 的大多数组件，特别是 `<Link />` 和 `<Switch />`，必须是某个 Router 组件（例如 `<BrowserRouter />`）的（深层）子元素。通常在应用程序中只需要一个 Router，通常由最顶层的 `<App />` 组件立即渲染。Router 注册了一个上下文，这是 Links 和 Switches 功能所需的。下面提供了一个示例。\n\n:::caution\n在浏览器环境中使用 `yew-router` 时，强烈推荐使用 `<BrowserRouter />`。您可以在 [API 参考](https://docs.rs/yew-router/) 中找到其他路由器类型。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### 路径段\n\n路由还可以使用动态和命名通配符段从路由中提取信息。然后，您可以在 `<Switch />` 内访问帖子的 id，并通过属性将其转发到相应的组件。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n您也可以使用普通的 `Post` 变体，而不是 `Post {id: String}`。例如，当 `Post` 与另一个路由器一起渲染时，该字段可能是多余的，因为另一个路由器可以匹配并处理路径。有关详细信息，请参阅下面的[嵌套路由器](#nested-router)部分。\n:::\n\n请注意，字段必须实现 `Clone + PartialEq` 作为 `Route` 枚举的一部分。它们还必须实现 `std::fmt::Display` 和 `std::str::FromStr` 以进行序列化和反序列化。整数、浮点数和字符串等原始类型已经满足这些要求。\n\n当路径的形式匹配，但反序列化失败（根据 `FromStr`）时。路由器将认为路由不匹配，并尝试渲染未找到的路由（或者如果未指定未找到的路由，则渲染空白页面）。\n\n参考以下示例：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// 切换函数会渲染 News 和 id。这里省略了。\n```\n\n当段超过 255 时，`u8::from_str()` 将失败并返回 `ParseIntError`，路由器将认为路由不匹配。\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\n有关路由语法和如何绑定参数的更多信息，请查看 [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params)。\n\n### 位置 (Location)\n\n路由器通过上下文提供了一个通用的 `Location` 结构，可以用于访问路由信息。它们可以通过钩子或 `ctx.link()` 上的便捷函数来检索。\n\n### 导航\n\n`yew_router` 提供了一些工具来处理导航。\n\n#### 链接\n\n`<Link />` 渲染为 `<a>` 元素，`onclick` 事件处理程序将调用 [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)，并将目标页面推送到历史记录中并渲染所需的页面，这正是单页应用程序所期望的行为。普通锚元素的默认 `onclick` 会重新加载页面。\n\n`<Link />` 组件还会将其子元素传递给 `<a>` 元素。可以将其视为应用内路由的 `<a/>` 替代品。不同之处在于你需要提供 `to` 属性而不是 `href`。示例用法如下：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n结构体变量也可以正常工作：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### 导航接口\n\n导航器 API 为函数组件和结构组件提供。它们使回调能够更改路由。可以在任一情况下获取 `Navigator` 实例以操作路由。\n\n##### 函数式组件\n\n对于函数组件，当底层导航器提供程序更改时，`use_navigator` 钩子会重新渲染组件。\n以下是实现一个按钮的示例，该按钮在点击时导航到 `Home` 路由。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\n这里的示例使用了 `Callback::from`。如果目标路由可以与组件所在的路由相同，或者只是为了安全起见，请使用普通的回调。例如，考虑在每个页面上都有一个徽标按钮，点击该按钮会返回主页。在主页上点击该按钮两次会导致代码崩溃，因为第二次点击会推送一个相同的 Home 路由，并且 `use_navigator` 钩子不会触发重新渲染。\n:::\n\n如果您想替换当前的位置而不是将新位置推到堆栈上，请使用 `navigator.replace()` 而不是 `navigator.push()`。\n\n您可能会注意到 `navigator` 必须移动到回调中，因此不能再次用于其他回调。幸运的是，`navigator` 实现了 `Clone`，例如，以下是如何为不同的路由设置多个按钮：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 结构体组件\n\n对于结构体组件，可以通过 `ctx.link().navigator()` API 获取 `Navigator` 实例。其余部分与函数组件的情况相同。以下是一个渲染单个按钮的视图函数示例。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### 重定向\n\n`yew-router` 还在 prelude 中提供了一个 `<Redirect />` 组件。它可以用于实现与导航器 API 类似的效果。该组件接受一个 `to` 属性作为目标路由。当渲染 `<Redirect/>` 时，用户将被重定向到属性中指定的路由。以下是一个示例：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // 建立对 `use_user` 的钩子\n    let user = match use_user() {\n        Some(user) => user,\n        // 当用户为 `None` 时重定向到登录页面\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 实际页面内容\n}\n```\n\n:::tip 如何选择 `Redirect` 或 `Navigator`\nNavigator API 是在回调中操作路由的唯一方法。\n而 `<Redirect />` 可以作为组件中的返回值使用。您可能还希望在其他非组件上下文中使用 `<Redirect />`，例如在[嵌套路由器](#nested-router)的 switch 函数中。\n:::\n\n### 监听变化\n\n#### 函数式组件\n\n您可以使用 `use_location` 和 `use_route` 钩子。当提供的值发生变化时，您的组件将重新渲染。\n\n#### 结构体组件\n\n为了响应路由变化，您可以将回调闭包传递给 `ctx.link()` 的 `add_location_listener()` 方法。\n\n:::note\n一旦位置监听器被删除，它将被取消注册。请确保将句柄存储在组件状态中。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // 处理事件\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` 和 `ctx.link().route::<R>()` 也可以用于一次性检索位置和路由。\n\n### 查询参数\n\n#### 在导航时指定查询参数\n\n为了在导航到新路由时指定查询参数，可以使用 `navigator.push_with_query` 或 `navigator.replace_with_query` 函数。它使用 `serde` 将参数序列化为 URL 的查询字符串，因此任何实现了 `Serialize` 的类型都可以传递。最简单的形式是包含字符串对的 `HashMap`。\n\n#### 获取当前路由的查询参数\n\n`location.query` 用于获取查询参数。它使用 `serde` 从 URL 的查询字符串中反序列化参数。\n\n## 嵌套路由器\n\n当应用程序变得更大时，嵌套路由器可能会很有用。考虑以下路由器结构：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\n嵌套的 `SettingsRouter` 处理所有以 `/settings` 开头的 URL。此外，它会将未匹配的 URL 重定向到主 `NotFound` 路由。因此，`/settings/gibberish` 将重定向到 `/404`。\n\n:::caution\n\n请注意，该接口仍在开发中，这样写的方式尚未最终确定\n\n:::\n\n可以使用以下代码实现：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### 基底路径 (Basename)\n\n可以使用 `yew-router` 定义基底路径 (Basename)。\n基底路径是所有路由的公共前缀。导航器 API 和 `<Switch />` 组件都支持基底路径设置。所有推送的路由都会加上基底路径前缀，所有的 switch 都会在尝试将路径解析为 `Routable` 之前去掉基底路径。\n\n如果没有为 Router 组件提供基底路径属性，它将使用 HTML 文件中 `<base />` 元素的 href 属性，并在 HTML 文件中没有 `<base />` 元素时回退到 `/`。\n\n## 相关示例\n\n- [路由](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## 接口参考\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/concepts/suspense.mdx",
    "content": "---\ntitle: '占位标签 (Suspense)'\ndescription: '用于数据获取的占位标签'\n---\n\n占位标签 (Suspense) 是一种在等待任务完成前暂停组件渲染的方式，同时显示一个回退（占位符）UI。\n\n它可以用于从服务器获取数据，等待代理完成任务，或执行其他后台异步任务。\n\n在占位标签出现之前，数据获取通常发生在组件渲染之后（渲染时获取）或之前（获取后渲染）。\n\n### 边渲染，边下载\n\n占位标签 (Suspense) 提供了一种新的方法，允许组件在渲染过程中发起数据请求。当组件发起数据请求时，渲染过程将被暂停，并显示一个回退 UI，直到请求完成。\n\n推荐使用钩子 (Hook) 来使用占位标签。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n在上面的示例中，`use_user` 钩子将在加载用户信息时暂停组件渲染，并在加载 `user` 之前显示 `Loading...` 占位符。\n\n要定义一个暂停组件渲染的钩子，它需要返回一个 `SuspensionResult<T>`。当组件需要被暂停时，钩子应该返回一个 `Err(Suspension)`，用户应该使用 `?` 解包它，这样它将被转换为 `Html`。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 当用户加载完成时，我们将其作为 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 当用户仍在加载时，我们创建一个 `Suspension`\n            // 并在数据加载完成时调用 `SuspensionHandle::resume`，\n            // 组件将自动重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### 关于实现暂停钩子 (Hook) 的注意事项\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) 返回 2 个值：暂停上下文本身和一个暂停句柄。后者负责在何时重新渲染暂停的组件，它提供了 2 种可互换的方法：\n\n1. 调用其 [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) 方法。\n2. 丢弃句柄。\n\n:::danger\n\n暂停句柄必须存储直到更新组件的时候，即使用新接收的数据；否则，暂停的组件将进入无限重新渲染循环，从而影响性能。\n在上面的示例中，暂停句柄通过移动到闭包中并传递给 `on_load_user_complete` 来保存。\n当虚拟用户加载时，将调用闭包，从而调用 `handle.resume()` 并重新渲染与暂停上下文相关的组件。\n\n:::\n\n# 完整示例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 如果用户已加载，则将其作为 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 当用户仍在加载时，我们创建一个 `Suspension`\n            // 并在数据加载完成时调用 `SuspensionHandle::resume`，\n            // 组件将自动重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 在结构体组件中使用占位标签\n\n直接暂停结构体组件是不可能的。然而，您可以使用一个函数组件作为[高阶组件](../advanced-topics/struct-components/hoc)来实现基于占位标签的数据获取。\n\nYew 仓库中的[占位标签示例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)演示了如何使用这个组件。\n\n## 相关示例\n\n- [占位标签](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: '构建一个示例应用'\n---\n\n当您的环境准备好后，您可以选择使用一个包含基本 Yew 应用所需样板的起始模板，或手动设置一个小项目。\n\n## 使用模板快速起步\n\n按照 [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) 的安装说明安装该工具，然后运行以下命令：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手动配置应用\n\n### 创建项目\n\n首先，请创建一个新的 cargo 项目。\n\n```bash\ncargo new yew-app\n```\n\n打开新创建的目录。\n\n```bash\ncd yew-app\n```\n\n### 运行一个 hello world 示例\n\n为了验证 Rust 环境是否设置正确，使用 `cargo run` 运行初始项目。您应该看到一个 \"Hello World!\" 消息。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### 将项目设置为 Yew web 应用\n\n为了将这个简单的命令行应用程序转换为一个基本的 Yew web 应用程序，需要进行一些更改。\n\n#### 更新 Cargo.toml\n\n将 `yew` 添加到依赖列表中。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在构建一个应用程序，你只需要 `csr` 特性。它将启用 `Renderer` 和所有与客户端渲染相关的代码。\n\n如果你正在制作一个库，请不要启用此特性，因为它会将客户端渲染逻辑拉入服务器端渲染包中。\n\n如果你需要 Renderer 进行测试或示例，你应该在 `dev-dependencies` 中启用它。\n\n:::\n\n#### 更新 main.rs\n\n我们需要生成一个模板，设置一个名为 `App` 的根组件，该组件渲染一个按钮，当点击时更新其值。用以下代码替换 `src/main.rs` 的内容。\n\n:::note\n`main` 函数中的 `yew::Renderer::<App>::new().render()` 调用启动您的应用程序并将其挂载到页面的 `<body>` 标签上。如果您想要使用任何动态属性启动您的应用程序，您可以使用 `yew::Renderer::<App>::with_props(..).render()`。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### 创建 index.html\n\n最后，在应用程序的根目录中添加一个 `index.html` 文件。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## 查看您的 Web 应用\n\n运行以下命令在本地构建和提供应用程序。\n\n```bash\ntrunk serve\n```\n\n:::info\n添加选项 '--open' 来打开您的默认浏览器 `trunk serve --open`。\n:::\n\nTrunk 将在您修改任何源代码文件时实时重新构建您的应用程序。\n默认情况下，服务器将在地址 '127.0.0.1' 的端口 '8080' 上监听 => [http://localhost:8080](http://127.0.0.1:8080)。\n要更改这部分配置，请创建以下文件并根据需要进行编辑：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 局域网上的监听地址\naddress = \"127.0.0.1\"\n# 广域网上的监听地址\n# address = \"0.0.0.0\"\n# 监听的端口\nport = 8000\n```\n\n## 恭喜\n\n您现在已经成功设置了您的 Yew 开发环境，并构建了您的第一个 Web 应用程序。\n\n尝试这个应用程序，并查看[示例](./examples.mdx)以进一步学习。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/getting-started/editor-setup.mdx",
    "content": "---\ntitle: '设置编辑器'\ndescription: '设置您的代码编辑器'\n---\n\n:::important 改进文档\n有在使用不同的编辑器？如有推荐，请随意添加您选择的编辑器的说明。\n:::\n\n## 为创建组件添加模板\n\n### JetBrains IDEs\n\n1. 从导航栏依次点击 File | Settings | Editor | Live Templates.\n2. 选择 Rust 并点击 + 图标添加新的 Live Template。\n3. 根据需要给它一个的名称和描述。\n4. 将以下代码片段粘贴到模板文本部分。\n5. 在右下角更改适用性，选择 Rust > Item > Module\n\n对于函数式组件，使用以下模板。\n\n- (可选) 点击编辑变量，并给 `tag` 一个合理的默认值，例如 \"div\"，用双引号。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n对于结构体组件，可以使用以下更复杂的模板。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. 从导航栏依次点击 File > Preferences > User Snippets.\n2. 选择 Rust 作为设置语言。\n3. 在 JSON 文件中添加以下代码片段：\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## 支持 `html!` 宏\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 扩展\n\n> 这是一个**正在进行中**的，**由社区维护**的项目！[请查看详细信息，并将相关的 bug 报告/问题/疑问直接发送到扩展的存储库](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 扩展 [可以在 VSC Marketplace 上找到](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)，提供语法高亮、重命名、悬停等功能。\n\nEmmet 支持应该可以直接使用，如果不能，请回退到编辑 `settings.json` 文件：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> 下面的配置适用于 [LazyVim](https://www.lazyvim.org) 配置和 lazy.vim 插件，请在 `lua/plugins/nvim-lspconfig.lua` 中创建一个文件（或更新您的 `lspconfig`）：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/getting-started/examples.mdx",
    "content": "---\ntitle: '示例'\n---\n\nYew 仓库包含许多[示例]（维护状态各异）。\n我们建议浏览它们以了解如何使用框架的不同功能。\n我们也欢迎拉取请求和问题，以便在它们不可避免地被忽略并需要一些帮助 ♥️ 时使用。\n\n有关更多详细信息，包括示例列表，请参阅[README]。\n\n:::note\n大多数示例都有一个可以在 https://examples.yew.rs/< example_name > 找到的在线部署。\n在各自的子文件夹中的 README 页面上点击它们的徽章以导航到在线演示。\n:::\n\n[示例列表]: https://github.com/yewstack/yew/tree/master/examples\n[示例文档 README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/getting-started/introduction.mdx",
    "content": "---\ntitle: '开始使用'\n---\n\n你需要一些工具来编译、构建、打包和调试你的 Yew 应用程序。在最开始，我们建议使用 [Trunk](https://trunkrs.dev/)。Trunk 是一个用于 Rust 的 WASM Web 应用程序打包工具。\n\n## 安装 Rust\n\n要安装 Rust，请按照[官方说明](https://www.rust-lang.org/tools/install)。\n\n:::important\nYew 支持的最低 Rust 版本（MSRV）是 `1.84.0`。旧版本将无法编译。您可以使用 `rustup show`（在“active toolchain”下）或 `rustc --version` 检查您的工具链版本。要更新您的工具链，请运行 `rustup update`。\n:::\n\n## 安装 WebAssembly 目标\n\nRust 可以为不同的“目标”（例如不同的处理器）编译源代码。用于基于浏览器的 WebAssembly 的编译目标称为 `wasm32-unknown-unknown`。以下命令将向您的开发环境添加 WebAssembly 目标。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## 安装 Trunk\n\nTrunk 是推荐的用于管理部署和打包的工具，并在整个文档和示例中使用。\n\n```shell\n# 需要注意的是，这可能需要一段时间来安装，因为它会从头开始编译所有内容\n# Trunk 还为许多主要的包管理器提供了预构建的二进制文件\n# 有关更多详细信息，请参见 https://trunkrs.dev/#install\ncargo install --locked trunk\n```\n\n### 其他选项\n\n除了 Trunk 之外，还有其他选项可用于打包 Yew 应用程序。您可能想尝试以下选项之一：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (仍在早期开发阶段)\n\n## 下一步\n\n设置好开发环境后，您现在可以继续阅读文档。如果您喜欢通过动手实践来学习，我们建议您查看我们的[教程](../tutorial)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: '从 0.22.0 迁移到 0.23.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` 不再在恒等分发时重新渲染\n\n`use_reducer` 现在在 reducer 返回相同的 `Rc` 时（通过指针相等性判断）会跳过重新渲染。之前，每次分发都会触发重新渲染。\n\n如果你的 reducer 有一个返回 `self` 不变的代码路径，并且你依赖它来触发重新渲染，请用 `use_force_update` 替代：\n\n<Tabs>\n  <TabItem value=\"before\" label=\"之前\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // 在 0.23 中这不再触发重新渲染！\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"刷新\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"之后\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"刷新\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: '从 0.4.0 迁移到 0.5.0'\n---\n\n没有破坏性变更。在 `Cargo.toml` 中将 yew-agent 更新到 0.5.0。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: '从 0.19.0 迁移到 0.20.0'\n---\n\n没有破坏性变更。在 `Cargo.toml` 中将 yew-router 更新到 0.20.0。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\n一个关于如何最好地将 CSS 支持集成到 Yew 中的讨论可以在这里找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n这里包含了很多关于如何最好地将 CSS 支持集成到 Yew 中的讨论。\n\n目前，我们采用的方法是鼓励开发者在采用最流行的系统之前构建许多系统。\n\n社区目前正在开发几个项目，以便为项目添加样式。以下是其中的一些：\n\n#### 组件库\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - 一个没有任何 JavaScript 依赖的 Yew 样式框架。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design 组件。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS 组件。\n- [Yewtify](https://github.com/yewstack/yewtify) – 在 Yew 中实现 Vuetify 框架提供的功能。\n\n#### 样式解决方案\n\n- [stylist](https://github.com/futursolo/stylist-rs) - 用于 WebAssembly 应用程序的 CSS-in-Rust 样式解决方案。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind 实用类。\n\n:::important 改进文档\n如果您正在开发一个为 Yew 添加样式的项目，请提交一个 PR 将自己添加到这个列表中！\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/more/debugging.mdx",
    "content": "---\ntitle: '调试'\n---\n\n## 意外终止 (Panics)\n\nYew 会自动在浏览器控制台中输出意外终止日志。\n\n## 控制台日志\n\n在 JavaScript 中，`console.log()` 用于输出到浏览器控制台。以下是一些 Yew 的选项。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate 与 [`log`](https://crates.io/crates/log) crate 集成，以将日志级别、源行和文件名发送到浏览器控制台。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\n这个 crate 是 Gloo 的一部分，提供了对浏览器 API 的 Rust 包装。`log!` 宏可以直接接受 `JsValue`，比 `wasm_logger` 更容易使用。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` 可以与 [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) 一起使用，将消息输出到浏览器控制台。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## 调试组件生命周期\n\n[`tracing`](https://crates.io/crates/tracing) 可以用于收集与组件生命周期相关的事件信息。`tracing` 还带有一个 `log` 支持的特性标志，可以与 `wasm-logger` 很好地集成。\n\n[编译时过滤器](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) 可以用于调整详细程度或禁用日志记录，这应该会导致更小的 Wasm 文件。\n\n## 源映射 (Source Maps)\n\n有一些支持 [源映射](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf)。但是，需要一些配置。\n\n## 过去的文章\n\n以下是一些关于 Rust 中 WebAssembly 调试状态的过去文章。它们可能是有趣的阅读。\n\n\\[Dec 2019\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 这些工作还有很多要做。例如，在工具方面，Emscripten（Binaryen）和 wasm-pack（wasm-bindgen）尚未支持在它们执行的转换上更新 DWARF 信息。\n\n\\[2020\\] [Rust Wasm 调试指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸的是，WebAssembly 的调试能力仍然不成熟。在大多数 Unix 系统上，[DWARF](http://dwarfstd.org/) 用于编码调试器需要提供运行中程序的源级检查的信息，就连在 Windows 上有一种编码类似信息的替代格式。但目前，WebAssembly 没有相应的格式。\n\n\\[2019\\] [Rust Wasm 路线图](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 调试很棘手，因为很多情况不在这个工作组的掌控之中，而是取决于 WebAssembly 标准化机构和实现浏览器开发者工具的人。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/more/deployment.mdx",
    "content": "---\ntitle: '部署'\ndescription: '部署 Yew 应用程序'\n---\n\n当您准备将 Yew 应用程序部署到服务器时，您有多种部署方案可以选择。\n\n`trunk build --release` 会以发布模式构建您的应用程序。设置您的 HTTP 服务器，以便在访问您的站点时提供 `index.html`，并且对于静态路径（例如 `index_<hash>.js` 和 `index_bg_<hash>.wasm`）的请求，应该从 trunk 生成的 dist 目录中提供相应的内容。\n\n:::important 有关 `trunk serve --release`\n不要在生产环境中使用 `trunk serve --release` 来提供您的应用程序。\n它只应该用于在开发过程中测试发布版本构建。\n:::\n\n## 服务器配置\n\n### 将 `index.html` 作为回退提供\n\n如果应用程序使用了 [Yew 路由](concepts/router.mdx)，您必须配置服务器在请求不存在的文件时返回 `index.html`。\n\n具有 Yew 路由的应用程序被构建为 [单页应用程序 (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA)。当用户从正在运行的客户端导航到 URL 时，路由器会解释 URL 并路由到该页面。\n\n但是在刷新页面或在地址栏中输入 URL 时，这些操作都是由浏览器本身处理的，而不是由正在运行的应用程序处理。浏览器直接向服务器请求该 URL，绕过了路由器。错误配置的服务器会返回 404 - 未找到 状态。\n\n通过返回 `index.html`，应用程序会像通常一样加载，就好像请求是 `/`，直到路由器注意到路由是 `/show/42` 并显示相应的内容。\n\n### 为 Web Assembly 资源配置正确的 MIME 类型。\n\nWASM 文件必须使用 `application/wasm` MIME 类型设置 [Content-Type 头](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。\n\n大多数服务器和托管服务默认已经这样做。如果您的服务器没有这样做，请查阅其文档。在大多数 Web 浏览器中，错误的 MIME 类型会导致类似以下的错误：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 为相对路径构建\n\n默认情况下，trunk 会假定您的站点在 `/` 处提供，并相应地构建站点。可以通过在 `index.html` 文件中添加 `<base data-trunk-public-url />` 来覆盖此行为。Trunk 会重写此标签以包含传递给 `--public-url` 的值。Yew 路由会自动检测 `<base />` 的存在并适当处理。\n\n## 使用环境变量自定义行为\n\n通常使用环境变量来自定义构建环境。由于应用程序在浏览器中运行，我们无法在运行时读取环境变量。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) 宏可以在编译时获取环境变量的值。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/more/roadmap.mdx",
    "content": "---\ntitle: '路线图'\ndescription: 'Yew 框架的计划功能路线图'\n---\n\n## 优先级\n\n框架即将推出的功能和重点的优先级由社区决定。\n在 2020 年春季，我们发送了一份开发者调查，以收集关于项目方向的反馈。\n您可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到调查摘要。\n\n:::note\n所有主要倡议的状态都可以在 Yew Github [项目看板](https://github.com/yewstack/yew/projects) 上跟踪\n:::\n\n## 重点\n\n1. 最受欢迎的功能\n2. 生产就绪\n3. 文档\n4. 痛点\n\n### 最受欢迎的功能\n\n1. [函数组件](https://github.com/yewstack/yew/projects/3)\n2. [组件库](https://github.com/yewstack/yew/projects/4)\n3. 更好的状态管理\n4. [服务器端渲染](https://github.com/yewstack/yew/projects/5)\n\n### 生产就绪所需的问题\n\n- 提高 Yew 测试覆盖率\n- 减小二进制文件大小\n- [性能基准测试](https://github.com/yewstack/yew/issues/5)\n\n### 文档\n\n- 创建教程\n- 简化项目设置\n\n### 痛点\n\n- [组件样板](https://github.com/yewstack/yew/issues/830)\n- [代理](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/more/testing.mdx",
    "content": "---\ntitle: '测试应用'\ndescription: '测试你的应用'\n---\n\n:::info\n我们正在努力让测试组件变得更容易，但目前仍在进行中。\n\n在 GitHub 仓库中可以找到对 [浅渲染](https://github.com/yewstack/yew/issues/1413) 的支持。\n:::\n\n## 快照测试\n\nYew 提供了 `yew::tests::layout_tests` 模块来方便组件的快照测试。\n\n:::important 改进文档\n我们需要帮助，以改进快照测试的文档。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM 工作组维护了一个叫做 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) 的 crate，\n它允许你以类似于内置的 `#[test]` 过程宏的方式在浏览器中运行测试。\n有关此模块的更多信息，请参阅 [Rust Wasm 工作组的文档](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23/tutorial/index.mdx",
    "content": "---\ntitle: '教程'\nslug: /tutorial\n---\n\n## 介绍\n\n在这个实践教程中，我们将学习如何使用 Yew 构建 Web 应用程序。\n**Yew** 是一个现代的 [Rust](https://www.rust-lang.org/) 框架，用于使用 [WebAssembly](https://webassembly.org/) 构建前端 Web 应用程序。\nYew 通过利用 Rust 强大的类型系统，鼓励可重用、可维护和良好结构化的架构。\n一个庞大的社区创建的库生态系统，称为 Rust 中的 [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)，为常用模式（如状态管理）提供了组件。\nRust 的包管理器 [Cargo](https://doc.rust-lang.org/cargo/) 允许我们利用 [crates.io](https://crates.io) 上提供的大量 crate，例如 Yew。\n\n### 我们将要构建的内容\n\nRustconf 是 Rust 社区每年举办的星际聚会。\nRustconf 2020 有大量的演讲，提供了大量的信息。\n在这个实践教程中，我们将构建一个 Web 应用程序，帮助其他 Rustaceans 了解这些演讲并从一个页面观看它们。\n\n## 设置\n\n### 先决条件\n\n这个教程假设您已经熟悉 Rust。如果您是 Rust 的新手，免费的 [Rust 书](https://doc.rust-lang.org/book/ch00-00-introduction.html) 为初学者提供了一个很好的起点，并且即使对于有经验的 Rust 开发人员来说，它仍然是一个很好的资源。\n\n确保安装了最新版本的 Rust，方法是运行 `rustup update` 或者[安装 Rust](https://www.rust-lang.org/tools/install)。\n\n安装 Rust 后，您可以使用 Cargo 运行以下命令安装 `trunk`：\n\n```bash\ncargo install trunk\n```\n\n我们还需要添加 WASM 构建目标，运行以下命令：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### 设置项目\n\n首先，创建一个新的 cargo 项目：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\n为了验证 Rust 环境是否设置正确，使用 cargo 构建工具运行初始项目。\n在关于构建过程的输出之后，您应该看到预期的 \"Hello, world!\" 消息。\n\n```bash\ncargo run\n```\n\n## 我们的第一个静态页面\n\n为了将这个简单的命令行应用程序转换为一个基本的 Yew web 应用程序，需要进行一些更改。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在构建一个应用程序，你只需要 `csr` 特性。它将启用 `Renderer` 和所有与客户端渲染相关的代码。\n\n如果你正在制作一个库，请不要启用此特性，因为它会将客户端渲染逻辑拉入服务器端渲染包中。\n\n如果你需要 Renderer 进行测试或示例，你应该在 `dev-dependencies` 中启用它。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n现在，让我们在项目的根目录创建一个 `index.html`。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 启动开发服务器\n\n运行以下命令构建并在本地提供应用程序。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n删除选项 '--open' 以在运行 `trunk serve` 后不打开默认浏览器。\n:::\n\nTrunk 将在您修改任何源代码文件时实时重新构建您的应用程序。\n默认情况下，服务器将在地址 '127.0.0.1' 的端口 '8080' 上监听 => [http://localhost:8080](http://127.0.0.1:8080)。\n要更改这部分配置，请创建以下文件并根据需要进行编辑：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 局域网上的监听地址\naddress = \"127.0.0.1\"\n# 广域网上的监听地址\n# address = \"0.0.0.0\"\n# 监听的端口\nport = 8000\n```\n\n如果您感兴趣，您可以运行 `trunk help` 和 `trunk help <subcommand>` 以获取更多关于正在进行的流程的详细信息。\n\n### 恭喜\n\n您现在已经成功设置了 Yew 开发环境，并构建了您的第一个 Yew Web 应用程序。\n\n## 构建 HTML\n\nYew 利用了 Rust 的过程宏，并为我们提供了一种类似于 JSX（JavaScript 的扩展，允许您在 JavaScript 中编写类似 HTML 的代码）的语法来创建标记。\n\n### 转换为经典 HTML\n\n由于我们已经对我们的网站长什么样有了一个很好的想法，我们可以简单地将我们的草稿转换为与 `html!` 兼容的表示。如果您习惯于编写简单的 HTML，那么您在 `html!` 中编写标记时应该没有问题。需要注意的是，这个宏与 HTML 有一些不同之处：\n\n1. 表达式必须用大括号（`{ }`）括起来\n2. 只能有一个根节点。如果您想要在不将它们包装在容器中的情况下拥有多个元素，可以使用空标签/片段（`<> ... </>`）\n3. 元素必须正确关闭。\n\n我们想要构建一个布局，原始 HTML 如下：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\n现在，让我们将这个 HTML 转换为 `html!`。将以下代码片段输入（或复制/粘贴）到 `app` 函数的主体中，以便函数返回 `html!` 的值\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\n刷新浏览器页面，您应该看到以下输出：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### 在标记中使用 Rust 语言结构\n\n在 Rust 中编写标记的一个很大的优势是，我们在标记中获得了 Rust 的所有优点。\n现在，我们不再在 HTML 中硬编码视频列表，而是将它们定义为 `Vec` 的 `Video` 结构体。\n我们创建一个简单的 `struct`（在 `main.rs` 或我们选择的任何文件中）来保存我们的数据。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n接下来，我们将在 `app` 函数中创建这个结构体的实例，并使用它们来替代硬编码的数据：\n\n```rust\nuse website_test::tutorial::Video; // 换成你自己的路径\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\n为了显示它们，我们需要将 `Vec` 转换为 `Html`。我们可以通过创建一个迭代器，将其映射到 `html!` 并将其收集为 `Html` 来实现：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\n在列表项上使用键有助于 Yew 跟踪列表中哪些项发生了变化，从而实现更快的重新渲染。[始终建议在列表中使用键](/concepts/html/lists.mdx#keyed-lists)。\n:::\n\n最后，我们需要用从数据创建的 `Html` 替换硬编码的视频列表：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## 组件\n\n组件是 Yew 应用程序的构建块。通过组合组件（可以由其他组件组成），我们构建我们的应用程序。通过为可重用性构建组件并保持它们的通用性，我们将能够在应用程序的多个部分中使用它们，而无需重复代码或逻辑。\n\n到目前为止我们一直在使用的 `app` 函数是一个组件，称为 `App`。它是一个“函数式组件”。\n\n1. 结构体组件\n2. 函数式组件\n\n在本教程中，我们将使用函数式组件。\n\n现在，让我们将 `App` 组件拆分为更小的组件。我们首先将视频列表提取到自己的组件中。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n注意我们的 `VideosList` 函数组件的参数。函数组件只接受一个参数，该参数定义了它的 \"props\"（\"properties\" 的缩写）。Props 用于从父组件传递数据到子组件。在这种情况下，`VideosListProps` 是一个定义 props 的结构体。\n\n:::important\n用于 props 的结构体必须通过派生实现 `Properties`。\n:::\n\n为了使上面的代码编译通过，我们需要修改 `Video` 结构体如下：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n现在，我们可以更新我们的 `App` 组件以使用 `VideosList` 组件。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n通过查看浏览器窗口，我们可以验证列表是否按预期呈现。我们已经将列表的渲染逻辑移动到了它的组件中。这缩短了 `App` 组件的源代码，使我们更容易阅读和理解。\n\n### 使应用可以交互\n\n这里的最终目标是显示所选视频。为了做到这一点，`VideosList` 组件需要在选择视频时“通知”其父组件，这是通过 `Callback` 完成的。这个概念称为“传递处理程序”。我们修改其 props 以接受一个 `on_click` 回调：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n然后我们修改 `VideosList` 组件以将所选视频传递给回调。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n接下来，我们需要修改 `VideosList` 的使用以传递该回调。但在这样做之前，我们应该创建一个新的组件 `VideoDetails`，当点击视频时才会显示。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n现在，修改 `App` 组件以在选择视频时显示 `VideoDetails` 组件。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n现在不用担心 `use_state`，我们稍后会回到这个问题。注意我们用 `{ for details }` 提取列表数据的技巧。\n`Option<_>` 实现了 `Iterator`，所以我们可以使用特殊的 `{ for ... }` 语法来逐个显示 `Iterator` 返回的唯一元素，而这[由 `html!` 宏支持](concepts/html/lists)。\n\n### 处理状态\n\n还记得之前使用的 `use_state` 吗？那是一个特殊的函数，称为 \"hook\"。Hooks 用于 \"hook\" 到函数组件的生命周期中并执行操作。您可以在[这里](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)了解更多关于这个 hook 和其他 hook 的信息。\n\n:::note\n结构体组件的行为不同。请查看[文档](advanced-topics/struct-components/introduction.mdx)了解有关这些的信息。\n:::\n\n## 获取数据（使用外部 REST API）\n\n在真实的应用程序中，数据通常来自 API 而不是硬编码。让我们从外部源获取我们的视频列表。为此，我们需要添加以下 crate：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  用于进行 fetch 调用。\n- [`serde`](https://serde.rs) 和其派生特性\n  用于反序列化 JSON 响应\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  用于将 Rust 的 Future 作为 Promise 执行\n\n让我们更新 `Cargo.toml` 文件中的依赖项：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n在选择依赖项时，请确保它们与 `wasm32` 兼容！否则，您将无法运行您的应用程序。\n:::\n\n更新 `Video` 结构体以派生 `Deserialize` 特性：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n作为最后一步，我们需要更新我们的 `App` 组件，以便进行 fetch 请求，而不是使用硬编码的数据\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\n我们在这里使用 `unwrap`，因为这是一个演示应用程序。在真实的应用程序中，您可能希望有[适当的错误处理](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)。\n:::\n\n现在，查看浏览器，看看一切是否按预期工作……如果不是因为 CORS 的话。为了解决这个问题，我们需要一个代理服务器。幸运的是 trunk 提供了这个功能。\n\n更新这些行：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n现在，使用以下命令重新运行服务器：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\n刷新网页，一切应该按预期工作。\n\n## 总结\n\n恭喜！您已经创建了一个从外部 API 获取数据并显示视频列表的 Web 应用程序。\n\n## 接下来\n\n这个应用程序离完美或有用还有很长的路要走。在完成本教程后，您可以将其作为探索更高级主题的起点。\n\n### 样式\n\n我们的应用程序看起来非常丑陋。没有 CSS 或任何样式。不幸的是，Yew 没有提供内置的样式组件。请查看 [Trunk 的 assets](https://trunkrs.dev/assets/)，了解如何添加样式表。\n\n### 更多依赖库\n\n我们的应用程序只使用了很少的外部依赖。有很多 crate 可以使用。请查看[外部库](/community/external-libs)以获取更多详细信息。\n\n### 了解更多关于 Yew\n\n阅读我们的[官方文档](../getting-started/introduction.mdx)。它更详细地解释了许多概念。要了解有关 Yew API 的更多信息，请查看我们的[API 文档](https://docs.rs/yew)。\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-0.23.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.23\",\n    \"description\": \"The label for version 0.23\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"从零开始\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"核心概念\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew 核心概念\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"了解 Yew 的重要概念！\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"函数式组件\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"高级主题\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"高级主题\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"了解 Yew 的更多内部细节！\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"更多\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"杂项\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"迁移指南\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Yew 中的基本 Web 技术\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew 对基本 Web 技术的看法\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew 主要基于将可重用的 UI 部件所需的所有内容放在一个地方 - rust 文件的想法。但也力求保持与技术的原始外观接近。进一步探索，以充分理解我们对这些陈述的含义：\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"钩子\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"结构化组件\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs-community/current.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-docs-router/current.json",
    "content": "{\n    \"version.label\": {\n        \"message\": \"Next\",\n        \"description\": \"The label for version current\"\n    }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-plugin-content-pages/index.mdx",
    "content": "---\ntitle: 介绍\nslug: /\n---\n\n## Yew 是什么？\n\n**Yew** 是一个设计先进的 [Rust](https://www.rust-lang.org/) 框架，目的是使用 [WebAssembly](https://webassembly.org/) 来创建多线程的前端 web 应用。\n\n- **基于组件的框架**，可以轻松的创建交互式 UI。拥有 [React](https://reactjs.org/) 或 [Elm](https://elm-lang.org/) 等框架经验的开发人员在使用 Yew 时会感到得心应手。\n- **高性能** ，前端开发者可以轻易的将工作分流至后端来减少 DOM API 的调用，从而达到异常出色的性能。\n- **支持与 JavaScript 交互** ，允许开发者使用 NPM 包，并与现有的 JavaScript 应用程序结合。\n\n### 加入我们 😊\n\n- 你可以在这里 [GitHub issues page](https://github.com/yewstack/yew/issues) 报告 Bugs 或者是提出新的想法。\n- 我们欢迎 pull requests 。 如果你想要帮助我们，先参考下 [good first issues](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) 吧！\n- 我们的 [Discord chat](https://discord.gg/VQck8X4) 非常的热闹，也是一个问问题和解决问题的好地方！\n\n### 准备好开始了吗？\n\n点击下面的链接，来学习并编写你的第一个 Yew 前端 App ， 并通过丰富的社区示例项目来学习。\n\n[项目设置](docs/getting-started/introduction)\n\n### 还没有完全信服？\n\nYew 项目基于划时代的新技术，非常适合那些希望开发未来基础项目的开发者。接下来是一些我们相信 Yew 这样的框架将为成为未来 Web 开发的主流。\n\n#### 等等，为什么选用 WebAssembly?\n\nWebAssembly _(Wasm)_ 是一种可移植的底层语言，并且可以由 Rust 编译而来。它在浏览器中可以以原生速度运行，还同时支持和 JavaScript 交互。这些在所有的主流浏览器中都已经提供。希望了解更多关于 WebAssembly 是如何为前端应用提速的，可以查看官方[用例](https://webassembly.org/docs/use-cases/).\n\n值得注意的是，Wasm（目前还）并不是提高 Web 应用性能的万金油（原文：A Silver Bullet）就目前来说，在 WebAssembly 中使用 DOM API 仍然比从 JavaScript 中调用要慢。但只是暂时性问题的，[WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) 计划将解决这个问题。如果你想要了解更多关于这方面的信息，可以查看 Mozilla 的这篇[佳作](https://hacks.mozilla.org/2019/08/webassembly-interface-types/) 。\n\n#### 好的，那为什么选用 Rust 呢？\n\nRust 是一门运行速度超快，并且以他丰富的类型系统和可信赖的所有权模型而闻名的语言。尽管它的学习曲线非常的陡峭，但是带来的回报完全成正比！Rust 已经连续五年在 Stack Overflow 开发者调查报告中被评选为最受喜爱的编程语言：[2016](https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted)，[2017](https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted)，[2018](https://insights.stackoverflow.com/survey/2018#technology-_-most-loved-dreaded-and-wanted-languages) ， [2019](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages) 和 [2020](https://insights.stackoverflow.com/survey/2020#most-loved-dreaded-and-wanted)。\n\nRust 同样可以用它丰富的类型系统和可信赖的所有权模型来帮助开发者编写出更加安全的代码。和那些在 JavaScript 中难以定位的竞争条件 Bug 们说再见吧！ 事实上，通过 Rust ，大部分的 Bugs 都将在项目上线之前的编写阶段被编译器发现。同时不用担心，当你的应用出现错误的时候，你仍然可以在浏览器的调试控制台中获得你 Rust 代码的完整的错误栈追踪。\n\n#### 同类的项目？\n\n我们非常愿意和其他的类似项目交流想法，并且相信通过这种方式，我们可以互相扶持进步来发挥出这个新技术的潜力。如果你对 Yew 没有兴趣，你可能会喜欢这些项目。\n\n- [Percy](https://github.com/chinedufn/percy) - _\"A modular toolkit for building isomorphic web apps with Rust + WebAssembly\"_\n- [Seed](https://github.com/seed-rs/seed) - _\"A Rust framework for creating web apps\"_\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-theme-classic/footer.json",
    "content": "{\n  \"link.title.Support\": {\n    \"message\": \"Support\",\n    \"description\": \"The title of the footer links column with title=Support in the footer\"\n  },\n  \"link.title.Participate\": {\n    \"message\": \"Participate\",\n    \"description\": \"The title of the footer links column with title=Participate in the footer\"\n  },\n  \"link.title.More\": {\n    \"message\": \"More\",\n    \"description\": \"The title of the footer links column with title=More in the footer\"\n  },\n  \"link.item.label.Sponsor Project\": {\n    \"message\": \"Sponsor Project\",\n    \"description\": \"The label of footer link with label=Sponsor Project linking to https://opencollective.com/yew\"\n  },\n  \"link.item.label.GitHub\": {\n    \"message\": \"GitHub\",\n    \"description\": \"The label of footer link with label=GitHub linking to https://github.com/yewstack/yew\"\n  },\n  \"link.item.label.Discord\": {\n    \"message\": \"Discord\",\n    \"description\": \"The label of footer link with label=Discord linking to https://discord.gg/VQck8X4\"\n  },\n  \"link.item.label.Twitter\": {\n    \"message\": \"Twitter\",\n    \"description\": \"The label of footer link with label=Twitter linking to https://twitter.com/yewstack\"\n  },\n  \"link.item.label.Yew Awesome\": {\n    \"message\": \"Yew Awesome\",\n    \"description\": \"The label of footer link with label=Yew Awesome linking to https://github.com/jetli/awesome-yew\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hans/docusaurus-theme-classic/navbar.json",
    "content": "{\n  \"title\": {\n    \"message\": \"Yew\",\n    \"description\": \"The title in the navbar\"\n  },\n  \"item.label.Docs\": {\n    \"message\": \"Docs\",\n    \"description\": \"Navbar item with label Docs\"\n  },\n  \"item.label.API\": {\n    \"message\": \"API\",\n    \"description\": \"Navbar item with label API\"\n  },\n  \"item.label.GitHub\": {\n    \"message\": \"GitHub\",\n    \"description\": \"Navbar item with label GitHub\"\n  },\n  \"item.label.Community\": {\n    \"message\": \"Community\",\n    \"description\": \"Navbar item with label Community\"\n  },\n  \"item.label.Tutorial\": {\n    \"message\": \"Tutorial\",\n    \"description\": \"Navbar item with label Tutorial\"\n  },\n  \"item.label.Blog\": {\n    \"message\": \"Blog\",\n    \"description\": \"Navbar item with label Blog\"\n  },\n  \"item.label.Playground\": {\n    \"message\": \"Playground\",\n    \"description\": \"Navbar item with label Playground\"\n  },\n  \"logo.alt\": {\n    \"message\": \"Yew Logo\",\n    \"description\": \"The alt text of navbar logo\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/code.json",
    "content": "{\n  \"theme.ErrorPageContent.title\": {\n    \"message\": \"This page crashed.\",\n    \"description\": \"The title of the fallback page when the page crashed\"\n  },\n  \"theme.ErrorPageContent.tryAgain\": {\n    \"message\": \"Try again\",\n    \"description\": \"The label of the button to try again rendering when the React error boundary captures an error\"\n  },\n  \"theme.NotFound.title\": {\n    \"message\": \"Page Not Found\",\n    \"description\": \"The title of the 404 page\"\n  },\n  \"theme.NotFound.p1\": {\n    \"message\": \"We could not find what you were looking for.\",\n    \"description\": \"The first paragraph of the 404 page\"\n  },\n  \"theme.NotFound.p2\": {\n    \"message\": \"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.\",\n    \"description\": \"The 2nd paragraph of the 404 page\"\n  },\n  \"theme.AnnouncementBar.closeButtonAriaLabel\": {\n    \"message\": \"Close\",\n    \"description\": \"The ARIA label for close button of announcement bar\"\n  },\n  \"theme.BackToTopButton.buttonAriaLabel\": {\n    \"message\": \"Scroll back to top\",\n    \"description\": \"The ARIA label for the back to top button\"\n  },\n  \"theme.blog.archive.title\": {\n    \"message\": \"Archive\",\n    \"description\": \"The page & hero title of the blog archive page\"\n  },\n  \"theme.blog.archive.description\": {\n    \"message\": \"Archive\",\n    \"description\": \"The page & hero description of the blog archive page\"\n  },\n  \"theme.blog.paginator.navAriaLabel\": {\n    \"message\": \"Blog list page navigation\",\n    \"description\": \"The ARIA label for the blog pagination\"\n  },\n  \"theme.blog.paginator.newerEntries\": {\n    \"message\": \"Newer Entries\",\n    \"description\": \"The label used to navigate to the newer blog posts page (previous page)\"\n  },\n  \"theme.blog.paginator.olderEntries\": {\n    \"message\": \"Older Entries\",\n    \"description\": \"The label used to navigate to the older blog posts page (next page)\"\n  },\n  \"theme.blog.post.readingTime.plurals\": {\n    \"message\": \"{readingTime} min read\",\n    \"description\": \"Pluralized label for \\\"{readingTime} min read\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.blog.post.readMore\": {\n    \"message\": \"Read More\",\n    \"description\": \"The label used in blog post item excerpts to link to full blog posts\"\n  },\n  \"theme.blog.post.paginator.navAriaLabel\": {\n    \"message\": \"Blog post page navigation\",\n    \"description\": \"The ARIA label for the blog posts pagination\"\n  },\n  \"theme.blog.post.paginator.newerPost\": {\n    \"message\": \"Newer Post\",\n    \"description\": \"The blog post button label to navigate to the newer/previous post\"\n  },\n  \"theme.blog.post.paginator.olderPost\": {\n    \"message\": \"Older Post\",\n    \"description\": \"The blog post button label to navigate to the older/next post\"\n  },\n  \"theme.blog.sidebar.navAriaLabel\": {\n    \"message\": \"Blog recent posts navigation\",\n    \"description\": \"The ARIA label for recent posts in the blog sidebar\"\n  },\n  \"theme.blog.post.plurals\": {\n    \"message\": \"{count} posts\",\n    \"description\": \"Pluralized label for \\\"{count} posts\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.blog.tagTitle\": {\n    \"message\": \"{nPosts} tagged with \\\"{tagName}\\\"\",\n    \"description\": \"The title of the page for a blog tag\"\n  },\n  \"theme.tags.tagsPageLink\": {\n    \"message\": \"View All Tags\",\n    \"description\": \"The label of the link targeting the tag list page\"\n  },\n  \"theme.CodeBlock.copyButtonAriaLabel\": {\n    \"message\": \"Copy code to clipboard\",\n    \"description\": \"The ARIA label for copy code blocks button\"\n  },\n  \"theme.CodeBlock.copied\": {\n    \"message\": \"Copied\",\n    \"description\": \"The copied button label on code blocks\"\n  },\n  \"theme.CodeBlock.copy\": {\n    \"message\": \"Copy\",\n    \"description\": \"The copy button label on code blocks\"\n  },\n  \"theme.docs.sidebar.expandButtonTitle\": {\n    \"message\": \"Expand sidebar\",\n    \"description\": \"The ARIA label and title attribute for expand button of doc sidebar\"\n  },\n  \"theme.docs.sidebar.expandButtonAriaLabel\": {\n    \"message\": \"Expand sidebar\",\n    \"description\": \"The ARIA label and title attribute for expand button of doc sidebar\"\n  },\n  \"theme.docs.paginator.navAriaLabel\": {\n    \"message\": \"Docs pages navigation\",\n    \"description\": \"The ARIA label for the docs pagination\"\n  },\n  \"theme.docs.paginator.next\": {\n    \"message\": \"Next\",\n    \"description\": \"The label used to navigate to the next doc\"\n  },\n  \"theme.docs.paginator.previous\": {\n    \"message\": \"Previous\",\n    \"description\": \"The label used to navigate to the previous doc\"\n  },\n  \"theme.docs.sidebar.collapseButtonTitle\": {\n    \"message\": \"Collapse sidebar\",\n    \"description\": \"The title attribute for collapse button of doc sidebar\"\n  },\n  \"theme.docs.sidebar.collapseButtonAriaLabel\": {\n    \"message\": \"Collapse sidebar\",\n    \"description\": \"The title attribute for collapse button of doc sidebar\"\n  },\n  \"theme.docs.tagDocListPageTitle.nDocsTagged\": {\n    \"message\": \"One doc tagged|{count} docs tagged\",\n    \"description\": \"Pluralized label for \\\"{count} docs tagged\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.docs.tagDocListPageTitle\": {\n    \"message\": \"{nDocsTagged} with \\\"{tagName}\\\"\",\n    \"description\": \"The title of the page for a docs tag\"\n  },\n  \"theme.docs.versions.unreleasedVersionLabel\": {\n    \"message\": \"This is unreleased documentation for {siteTitle} {versionLabel} version.\",\n    \"description\": \"The label used to tell the user that he's browsing an unreleased doc version\"\n  },\n  \"theme.docs.versions.unmaintainedVersionLabel\": {\n    \"message\": \"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.\",\n    \"description\": \"The label used to tell the user that he's browsing an unmaintained doc version\"\n  },\n  \"theme.docs.versions.latestVersionSuggestionLabel\": {\n    \"message\": \"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).\",\n    \"description\": \"The label used to tell the user to check the latest version\"\n  },\n  \"theme.docs.versions.latestVersionLinkLabel\": {\n    \"message\": \"latest version\",\n    \"description\": \"The label used for the latest version suggestion link label\"\n  },\n  \"theme.common.editThisPage\": {\n    \"message\": \"Edit this page\",\n    \"description\": \"The link label to edit the current page\"\n  },\n  \"theme.common.headingLinkTitle\": {\n    \"message\": \"Direct link to heading\",\n    \"description\": \"Title for link to heading\"\n  },\n  \"theme.lastUpdated.atDate\": {\n    \"message\": \" on {date}\",\n    \"description\": \"The words used to describe on which date a page has been last updated\"\n  },\n  \"theme.lastUpdated.byUser\": {\n    \"message\": \" by {user}\",\n    \"description\": \"The words used to describe by who the page has been last updated\"\n  },\n  \"theme.lastUpdated.lastUpdatedAtBy\": {\n    \"message\": \"Last updated{atDate}{byUser}\",\n    \"description\": \"The sentence used to display when a page has been last updated, and by who\"\n  },\n  \"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel\": {\n    \"message\": \"← Back to main menu\",\n    \"description\": \"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)\"\n  },\n  \"theme.navbar.mobileVersionsDropdown.label\": {\n    \"message\": \"Versions\",\n    \"description\": \"The label for the navbar versions dropdown on mobile view\"\n  },\n  \"theme.common.skipToMainContent\": {\n    \"message\": \"Skip to main content\",\n    \"description\": \"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation\"\n  },\n  \"theme.tags.tagsListLabel\": {\n    \"message\": \"Tags:\",\n    \"description\": \"The label alongside a tag list\"\n  },\n  \"theme.TOCCollapsible.toggleButtonLabel\": {\n    \"message\": \"On this page\",\n    \"description\": \"The label used by the button on the collapsible TOC component\"\n  },\n  \"theme.blog.post.readMoreLabel\": {\n    \"message\": \"Read more about {title}\",\n    \"description\": \"The ARIA label for the link to full blog posts from excerpts\"\n  },\n  \"theme.colorToggle.ariaLabel\": {\n    \"message\": \"Switch between dark and light mode (currently {mode})\",\n    \"description\": \"The ARIA label for the color mode toggle\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.dark\": {\n    \"message\": \"dark mode\",\n    \"description\": \"The name for the dark color mode\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.light\": {\n    \"message\": \"light mode\",\n    \"description\": \"The name for the light color mode\"\n  },\n  \"theme.docs.versionBadge.label\": {\n    \"message\": \"Version: {versionLabel}\"\n  },\n  \"theme.navbar.mobileLanguageDropdown.label\": {\n    \"message\": \"Languages\",\n    \"description\": \"The label for the mobile language switcher dropdown\"\n  },\n  \"theme.docs.breadcrumbs.home\": {\n    \"message\": \"主頁面\",\n    \"description\": \"The ARIA label for the home page in the breadcrumbs\"\n  },\n  \"theme.docs.breadcrumbs.navAriaLabel\": {\n    \"message\": \"頁面路徑\",\n    \"description\": \"The ARIA label for the breadcrumbs\"\n  },\n  \"theme.CodeBlock.wordWrapToggle\": {\n    \"message\": \"切換自動換行\",\n    \"description\": \"The title attribute for toggle word wrapping button of code block lines\"\n  },\n  \"theme.SearchBar.seeAll\": {\n    \"message\": \"See all results\"\n  },\n  \"theme.SearchBar.label\": {\n    \"message\": \"Search\",\n    \"description\": \"The ARIA label and placeholder for search button\"\n  },\n  \"theme.SearchPage.existingResultsTitle\": {\n    \"message\": \"Search results for \\\"{query}\\\"\",\n    \"description\": \"The search page title for non-empty query\"\n  },\n  \"theme.SearchPage.emptyResultsTitle\": {\n    \"message\": \"Search the documentation\",\n    \"description\": \"The search page title for empty query\"\n  },\n  \"theme.SearchPage.documentsFound.plurals\": {\n    \"message\": \"1 document found|{count} documents found\",\n    \"description\": \"Pluralized label for \\\"{count} documents found\\\". Use as much plural forms (separated by \\\"|\\\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)\"\n  },\n  \"theme.SearchPage.noResultsText\": {\n    \"message\": \"No documents were found\",\n    \"description\": \"The paragraph for empty search result\"\n  },\n  \"theme.admonition.note\": {\n    \"message\": \"備註\",\n    \"description\": \"The default label used for the Note admonition (:::note)\"\n  },\n  \"theme.admonition.tip\": {\n    \"message\": \"提示\",\n    \"description\": \"The default label used for the Tip admonition (:::tip)\"\n  },\n  \"theme.admonition.danger\": {\n    \"message\": \"危險\",\n    \"description\": \"The default label used for the Danger admonition (:::danger)\"\n  },\n  \"theme.admonition.info\": {\n    \"message\": \"信息\",\n    \"description\": \"The default label used for the Info admonition (:::info)\"\n  },\n  \"theme.admonition.caution\": {\n    \"message\": \"警告\",\n    \"description\": \"The default label used for the Caution admonition (:::caution)\"\n  },\n  \"theme.tags.tagsPageTitle\": {\n    \"message\": \"標籤\",\n    \"description\": \"The title of the tag list page\"\n  },\n  \"theme.NavBar.navAriaLabel\": {\n    \"message\": \"Main\",\n    \"description\": \"The ARIA label for the main navigation\"\n  },\n  \"theme.docs.sidebar.navAriaLabel\": {\n    \"message\": \"Docs sidebar\",\n    \"description\": \"The ARIA label for the sidebar navigation\"\n  },\n  \"theme.docs.sidebar.closeSidebarButtonAriaLabel\": {\n    \"message\": \"Close navigation bar\",\n    \"description\": \"The ARIA label for close button of mobile sidebar\"\n  },\n  \"theme.docs.sidebar.toggleSidebarButtonAriaLabel\": {\n    \"message\": \"Toggle navigation bar\",\n    \"description\": \"The ARIA label for hamburger menu button of mobile navigation\"\n  },\n  \"theme.admonition.warning\": {\n    \"message\": \"warning\",\n    \"description\": \"The default label used for the Warning admonition (:::warning)\"\n  },\n  \"theme.DocSidebarItem.expandCategoryAriaLabel\": {\n    \"message\": \"Expand sidebar category '{label}'\",\n    \"description\": \"The ARIA label to expand the sidebar category\"\n  },\n  \"theme.DocSidebarItem.collapseCategoryAriaLabel\": {\n    \"message\": \"Collapse sidebar category '{label}'\",\n    \"description\": \"The ARIA label to collapse the sidebar category\"\n  },\n  \"theme.SearchPage.inputPlaceholder\": {\n    \"message\": \"在此輸入搜尋字詞\",\n    \"description\": \"The placeholder for search page input\"\n  },\n  \"theme.SearchPage.inputLabel\": {\n    \"message\": \"搜尋\",\n    \"description\": \"The ARIA label for search page input\"\n  },\n  \"theme.SearchPage.algoliaLabel\": {\n    \"message\": \"透過 Algolia 搜尋\",\n    \"description\": \"The description label for Algolia mention\"\n  },\n  \"theme.SearchPage.fetchingNewResults\": {\n    \"message\": \"正在取得新的搜尋結果...\",\n    \"description\": \"The paragraph for fetching new search results\"\n  },\n  \"theme.SearchModal.searchBox.resetButtonTitle\": {\n    \"message\": \"清除查詢\",\n    \"description\": \"The label and ARIA label for search box reset button\"\n  },\n  \"theme.SearchModal.searchBox.cancelButtonText\": {\n    \"message\": \"取消\",\n    \"description\": \"The label and ARIA label for search box cancel button\"\n  },\n  \"theme.SearchModal.startScreen.recentSearchesTitle\": {\n    \"message\": \"最近搜索\",\n    \"description\": \"The title for recent searches\"\n  },\n  \"theme.SearchModal.startScreen.noRecentSearchesText\": {\n    \"message\": \"沒有最近搜索\",\n    \"description\": \"The text when there are no recent searches\"\n  },\n  \"theme.SearchModal.startScreen.saveRecentSearchButtonTitle\": {\n    \"message\": \"保存這個搜索\",\n    \"description\": \"The title for save recent search button\"\n  },\n  \"theme.SearchModal.startScreen.removeRecentSearchButtonTitle\": {\n    \"message\": \"從歷史記錄中刪除這個搜索\",\n    \"description\": \"The title for remove recent search button\"\n  },\n  \"theme.SearchModal.startScreen.favoriteSearchesTitle\": {\n    \"message\": \"收藏\",\n    \"description\": \"The title for favorite searches\"\n  },\n  \"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle\": {\n    \"message\": \"從收藏列表中刪除這個搜索\",\n    \"description\": \"The title for remove favorite search button\"\n  },\n  \"theme.SearchModal.errorScreen.titleText\": {\n    \"message\": \"無法獲取結果\",\n    \"description\": \"The title for error screen\"\n  },\n  \"theme.SearchModal.errorScreen.helpText\": {\n    \"message\": \"你可能需要檢查網路連接。\",\n    \"description\": \"The help text for error screen\"\n  },\n  \"theme.SearchModal.footer.selectText\": {\n    \"message\": \"選中\",\n    \"description\": \"The select text for footer\"\n  },\n  \"theme.SearchModal.footer.selectKeyAriaLabel\": {\n    \"message\": \"Enter 鍵\",\n    \"description\": \"The ARIA label for select key in footer\"\n  },\n  \"theme.SearchModal.footer.navigateText\": {\n    \"message\": \"導航\",\n    \"description\": \"The navigate text for footer\"\n  },\n  \"theme.SearchModal.footer.navigateUpKeyAriaLabel\": {\n    \"message\": \"向上鍵\",\n    \"description\": \"The ARIA label for navigate up key in footer\"\n  },\n  \"theme.SearchModal.footer.navigateDownKeyAriaLabel\": {\n    \"message\": \"向下鍵\",\n    \"description\": \"The ARIA label for navigate down key in footer\"\n  },\n  \"theme.SearchModal.footer.closeText\": {\n    \"message\": \"關閉\",\n    \"description\": \"The close text for footer\"\n  },\n  \"theme.SearchModal.footer.closeKeyAriaLabel\": {\n    \"message\": \"Esc 鍵\",\n    \"description\": \"The ARIA label for close key in footer\"\n  },\n  \"theme.SearchModal.footer.searchByText\": {\n    \"message\": \"搜索提供\",\n    \"description\": \"The 'Powered by' text for footer\"\n  },\n  \"theme.SearchModal.noResultsScreen.noResultsText\": {\n    \"message\": \"沒有結果：\",\n    \"description\": \"The text when there are no results\"\n  },\n  \"theme.SearchModal.noResultsScreen.suggestedQueryText\": {\n    \"message\": \"試試搜索\",\n    \"description\": \"The text for suggested query\"\n  },\n  \"theme.SearchModal.noResultsScreen.reportMissingResultsText\": {\n    \"message\": \"認為這個查詢應該有結果？\",\n    \"description\": \"The text for reporting missing results\"\n  },\n  \"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText\": {\n    \"message\": \"請告知我們。\",\n    \"description\": \"The link text for reporting missing results\"\n  },\n  \"theme.SearchModal.placeholder\": {\n    \"message\": \"搜索文檔\",\n    \"description\": \"The placeholder of the input of the DocSearch pop-up modal\"\n  },\n  \"theme.docs.DocCard.categoryDescription.plurals\": {\n    \"message\": \"{count} 個項目\",\n    \"description\": \"The default description for a category card in the generated index about how many items this category includes\"\n  },\n  \"theme.blog.author.pageTitle\": {\n    \"message\": \"{authorName} - {nPosts}\",\n    \"description\": \"The title of the page for a blog author\"\n  },\n  \"theme.blog.authorsList.pageTitle\": {\n    \"message\": \"Authors\",\n    \"description\": \"The title of the authors page\"\n  },\n  \"theme.blog.authorsList.viewAll\": {\n    \"message\": \"View All Authors\",\n    \"description\": \"The label of the link targeting the blog authors page\"\n  },\n  \"theme.contentVisibility.unlistedBanner.title\": {\n    \"message\": \"未列出頁\",\n    \"description\": \"The unlisted content banner title\"\n  },\n  \"theme.contentVisibility.unlistedBanner.message\": {\n    \"message\": \"此頁面未列出。搜索引擎不會對其索引，只有擁有直接連結的用戶才能訪問。\",\n    \"description\": \"The unlisted content banner message\"\n  },\n  \"theme.contentVisibility.draftBanner.title\": {\n    \"message\": \"Draft page\",\n    \"description\": \"The draft content banner title\"\n  },\n  \"theme.contentVisibility.draftBanner.message\": {\n    \"message\": \"This page is a draft. It will only be visible in dev and be excluded from the production build.\",\n    \"description\": \"The draft content banner message\"\n  },\n  \"theme.blog.author.noPosts\": {\n    \"message\": \"This author has not written any posts yet.\",\n    \"description\": \"The text for authors with 0 blog post\"\n  },\n  \"theme.colorToggle.ariaLabel.mode.system\": {\n    \"message\": \"系統模式\",\n    \"description\": \"The name for the system color mode\"\n  },\n  \"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel\": {\n    \"message\": \"展開下拉選單\",\n    \"description\": \"The ARIA label of the button to expand the mobile dropdown navbar item\"\n  },\n  \"theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel\": {\n    \"message\": \"收起下拉選單\",\n    \"description\": \"The ARIA label of the button to collapse the mobile dropdown navbar item\"\n  },\n  \"theme.IconExternalLink.ariaLabel\": {\n    \"message\": \"(opens in new tab)\",\n    \"description\": \"The ARIA label for the external link icon\"\n  },\n  \"theme.SearchModal.searchBox.placeholderText\": {\n    \"message\": \"Search docs\",\n    \"description\": \"The placeholder text for the main search input field\"\n  },\n  \"theme.SearchModal.searchBox.placeholderTextAskAi\": {\n    \"message\": \"Ask another question...\",\n    \"description\": \"The placeholder text when in AI question mode\"\n  },\n  \"theme.SearchModal.searchBox.placeholderTextAskAiStreaming\": {\n    \"message\": \"Answering...\",\n    \"description\": \"The placeholder text for search box when AI is streaming an answer\"\n  },\n  \"theme.SearchModal.searchBox.enterKeyHint\": {\n    \"message\": \"search\",\n    \"description\": \"The hint for the search box enter key text\"\n  },\n  \"theme.SearchModal.searchBox.enterKeyHintAskAi\": {\n    \"message\": \"enter\",\n    \"description\": \"The hint for the Ask AI search box enter key text\"\n  },\n  \"theme.SearchModal.searchBox.searchInputLabel\": {\n    \"message\": \"Search\",\n    \"description\": \"The ARIA label for search input\"\n  },\n  \"theme.SearchModal.searchBox.backToKeywordSearchButtonText\": {\n    \"message\": \"Back to keyword search\",\n    \"description\": \"The text for back to keyword search button\"\n  },\n  \"theme.SearchModal.searchBox.backToKeywordSearchButtonAriaLabel\": {\n    \"message\": \"Back to keyword search\",\n    \"description\": \"The ARIA label for back to keyword search button\"\n  },\n  \"theme.SearchModal.startScreen.recentConversationsTitle\": {\n    \"message\": \"Recent conversations\",\n    \"description\": \"The title for recent conversations\"\n  },\n  \"theme.SearchModal.startScreen.removeRecentConversationButtonTitle\": {\n    \"message\": \"Remove this conversation from history\",\n    \"description\": \"The title for remove recent conversation button\"\n  },\n  \"theme.SearchModal.resultsScreen.askAiPlaceholder\": {\n    \"message\": \"Ask AI: \",\n    \"description\": \"The placeholder text for Ask AI input\"\n  },\n  \"theme.SearchModal.askAiScreen.disclaimerText\": {\n    \"message\": \"Answers are generated with AI which can make mistakes. Verify responses.\",\n    \"description\": \"The disclaimer text for AI answers\"\n  },\n  \"theme.SearchModal.askAiScreen.relatedSourcesText\": {\n    \"message\": \"Related sources\",\n    \"description\": \"The text for related sources\"\n  },\n  \"theme.SearchModal.askAiScreen.thinkingText\": {\n    \"message\": \"Thinking...\",\n    \"description\": \"The text when AI is thinking\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonText\": {\n    \"message\": \"Copy\",\n    \"description\": \"The text for copy button\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonCopiedText\": {\n    \"message\": \"Copied!\",\n    \"description\": \"The text for copy button when copied\"\n  },\n  \"theme.SearchModal.askAiScreen.copyButtonTitle\": {\n    \"message\": \"Copy\",\n    \"description\": \"The title for copy button\"\n  },\n  \"theme.SearchModal.askAiScreen.likeButtonTitle\": {\n    \"message\": \"Like\",\n    \"description\": \"The title for like button\"\n  },\n  \"theme.SearchModal.askAiScreen.dislikeButtonTitle\": {\n    \"message\": \"Dislike\",\n    \"description\": \"The title for dislike button\"\n  },\n  \"theme.SearchModal.askAiScreen.thanksForFeedbackText\": {\n    \"message\": \"Thanks for your feedback!\",\n    \"description\": \"The text for thanks for feedback\"\n  },\n  \"theme.SearchModal.askAiScreen.preToolCallText\": {\n    \"message\": \"Searching...\",\n    \"description\": \"The text before tool call\"\n  },\n  \"theme.SearchModal.askAiScreen.duringToolCallText\": {\n    \"message\": \"Searching for \",\n    \"description\": \"The text during tool call\"\n  },\n  \"theme.SearchModal.askAiScreen.afterToolCallText\": {\n    \"message\": \"Searched for\",\n    \"description\": \"The text after tool call\"\n  },\n  \"theme.SearchModal.footer.submitQuestionText\": {\n    \"message\": \"Submit question\",\n    \"description\": \"The submit question text for footer\"\n  },\n  \"theme.SearchModal.footer.backToSearchText\": {\n    \"message\": \"Back to search\",\n    \"description\": \"The back to search text for footer\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-blog/options.json",
    "content": "{\n  \"title\": {\n    \"message\": \"Yew Blog\",\n    \"description\": \"The title for the blog used in SEO\"\n  },\n  \"description\": {\n    \"message\": \"Blog\",\n    \"description\": \"The description for the blog used in SEO\"\n  },\n  \"sidebar.title\": {\n    \"message\": \"Recent posts\",\n    \"description\": \"The label for the left sidebar\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/children.mdx",
    "content": "---\ntitle: '子組件'\n---\n\n:::caution\n\n檢查和操作 `Children` 往往會導致應用程式中令人驚訝且難以解釋的行為。這可能導致邊緣情況，並且通常不會產生預期的結果。如果您嘗試操作 `Children`，則應考慮其他方法。\n\nYew 支援將 `Html` 用作子元件屬性的類型。如果您不需要 `Children` 或 `ChildrenRenderer`，則應使用 `Html` 作為子元件。它沒有 `Children` 的缺點，且效能開銷較低。\n\n:::\n\n## 一般用法\n\n*大多數情況下，*當允許元件具有子元件時，您不關心元件具有的子元件的類型。在這種情況下，下面的範例就足夠了。\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## 進階用法\n\n### 類型化子元件\n\n在您希望將一種類型的元件作為子元件傳遞給您的元件的情況下，您可以使用 `yew::html::ChildrenWithProps<T>`。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## 帶有屬性的巢狀子元件\n\n如果包含元件對其子元件進行了類型化，則可以存取和變更巢狀元件的屬性。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 枚舉類型的子元件\n\n當然，有時您可能需要將子元件限制為幾種不同的元件。在這些情況下，您必須更深入地了解 Yew。\n\n這裡使用 [`derive_more`](https://github.com/JelteF/derive_more) 來提供更好的人體工學。如果您不想使用它，您可以為每個變體手動實現 `From`。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 現在，我們實現 `Into<Html>`，以便 yew 知道如何渲染 `Item`。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### 可選類型的子元件\n\n您也可以具有特定類型的單一可選子元件：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... 页面内容\n            </div>\n        }\n    }\n}\n\n// 页面组件可以选择是否附带侧边栏：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // 附带侧边栏的页面\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // 不附带侧边栏的页面\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## 進一步閱讀\n\n- 有關此模式的真實範例，請查閱 yew-router 的原始程式碼。有關更高級的範例，請查看 yew 儲存庫中的[相關範例清單](https://github.com/yewstack/yew/tree/master/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '工作原理'\ndescription: '關於框架的底層細節'\n---\n\n# 底層庫的內部細節\n\n## `html!` 巨集的內部\n\n`html!` macro 會將使用類似 HTML 的自訂語法所編寫的程式碼轉換為有效的 Rust 程式碼。使用這個巨集對於開發 Yew 應用程式並不是必需的，但是是建議的。這個巨集產生的程式碼使用了 Yew 的公共函式庫 API，如果你願意的話，可以直接使用。請注意，有些方法是有意未記錄的，以避免意外的誤用。隨著 `yew-macro` 的每次更新，產生的程式碼將會更加高效，並且可以處理任何破壞性的更改，而不需要對 `html!` 語法進行很多（如果有的話）修改。\n\n由於 `html!` 巨集允許您以聲明式的風格編寫程式碼，因此您的 UI 佈局程式碼將與為頁面產生的 HTML 非常相似。隨著您的應用程式變得更加互動式，您的程式碼庫變得更大，這種方式變得越來越有用。與手動編寫所有操作 DOM 的程式碼相比，巨集會為您處理好這一切。\n\n使用 `html!` 巨集可能會讓人感到非常神奇，但它並沒有什麼可隱藏的。如果您對它的工作原理感到好奇，可以嘗試展開您程式中的 `html!` 巨集呼叫。有一個有用的指令叫做 `cargo expand`，它允許您查看 Rust 巨集的展開。 `cargo expand` 並不是預設隨 `cargo` 一起提供的，所以如果您還沒有安裝它，您需要使用 `cargo install cargo-expand` 來安裝它。 [Rust-Analyzer](https://rust-analyzer.github.io/) 也提供了一個[從IDE 中取得巨集輸出的機制](https://rust-analyzer.github.io/manual.html #expand-macro-recursively)。\n\n`html!` 巨集的輸出通常非常簡潔！這是一個功能：機器產生的程式碼有時可能會與應用程式中的其他程式碼衝突。為了防止問題，`proc_macro` 遵循了「衛生」規則。一些例子包括：\n\n1. 為了確保正確引用 Yew 套件，巨集產生的程式碼中使用 `::yew::<module>`，而不是直接使用 `yew::<module>`。這也是為什麼呼叫 `::alloc::vec::Vec::new()` 而不是直接呼叫 `Vec::new()`。\n2. 由於可能有 trait 方法名稱衝突，使用 `<Type as Trait>` 來確保我們使用的是正確的 trait 成員。\n\n## 什麼是虛擬 DOM？\n\nDOM（\"文件物件模型\"）是由瀏覽器管理的 HTML 內容的表示。 \"虛擬\" DOM 只是 DOM 的一個記憶體中的副本。管理虛擬 DOM 會導致更高的記憶體開銷，但可以透過避免或延遲使用瀏覽器 API 來實現批次和更快的讀取。\n\n在記憶體中擁有 DOM 的副本對於促進使用聲明式 UI 的函式庫是有幫助的。與需要特定程式碼來描述如何根據使用者事件修改 DOM 不同，程式庫可以使用一種通用的方法來進行 DOM \"diffing\"。當 Yew 元件更新並希望更改其呈現方式時，Yew 庫將建立虛擬 DOM 的第二個副本，並直接將其與鏡像當前螢幕上的內容的虛擬 DOM 進行比較。兩者之間的 \"diff\"（差異）可以分解為增量更新，並與瀏覽器 API 一起應用。一旦更新應用，舊的虛擬 DOM 副本將被丟棄，新的副本將被保存以供將來的差異檢查。\n\n這種 \"diff\" 演算法可以隨著時間的推移進行最佳化，以提高複雜應用程式的效能。由於 Yew 應用程式是透過 WebAssembly 運行的，我們相信 Yew 在未來採用更複雜的演算法方面具有競爭優勢。\n\nYew 的虛擬 DOM 與瀏覽器 DOM 不完全一一對應。它還包括用於組織 DOM 元素的 \"列表\" 和 \"元件\"。列表可以簡單地是元素的有序列表，但也可以更強大。透過為每個清單元素新增 \"key\" 註解，應用程式開發人員可以幫助 Yew 進行額外的最佳化，以確保在清單變更時，計算差異更新所需的工作量最小。同樣，元件提供了自訂邏輯，指示是否需要重新渲染，以幫助提高效能。\n\n## Yew 調度器和元件範圍的事件循環\n\n_貢獻文件 - 深入解釋 `yew::scheduler` 和 `yew::html::scope` 的工作原理_\n\n## 進一步閱讀\n\n- [Rust 手冊中關於巨集的更多資訊](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` 的更多資訊](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` 的 API 文件](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/immutable.mdx",
    "content": "---\ntitle: '不可變型別'\ndescription: 'Yew 的不可變資料結構'\n---\n\n## 什麼是不可變型別？\n\n這些類型是您可以實例化但永遠不會更改值的類型。為了更新值，您必須實例化一個新值。\n\n## 為什麼使用不可變型別？\n\n與 React 一樣，屬性是從祖先傳播到子代的。這意味著屬性在每個元件更新時必須存在。這就是為什麼屬性應該——理想情況下——很容易克隆。為了實現這一點，我們通常將事物包裝在 `Rc` 中。\n\n不可變類型非常適合保存屬性的值，因為它們可以在從組件傳遞到組件時以很低的成本克隆。\n\n## 常見的不可變型別\n\nYew 推薦使用來自 `implicit-clone` crate 的以下不可變型別：\n\n- `IString`（在 Yew 中別名為 `AttrValue`）- 用於字串而不是 `String`\n- `IArray<T>` - 用於陣列/向量而不是 `Vec<T>`\n- `IMap<K, V>` - 用於映射而不是 `HashMap<K, V>`\n\n這些型別是引用計數（`Rc`）或靜態引用，使它們的克隆成本非常低。\n\n## 進一步閱讀\n\n- [不可變範例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '優化 & 最佳實踐'\nsidebar_label: Optimizations\ndescription: '讓您的應用程式獲得最佳效能'\n---\n\n## 使用智慧指針\n\n**注意：如果您對本節中使用的某些術語感到困惑，Rust 手冊中有一個有用的[關於智慧型指針的章節](https://doc.rust-lang.org/book/ch15-00- smart-pointers.html)。 **\n\n為了避免在重新渲染時克隆大量資料以創建 props，我們可以使用智慧指針，只克隆對資料的引用而不是資料本身。如果您在props 和子組件中傳遞與相關數據的引用而不是實際數據，您可以避免在需要修改數據的子組件中克隆任何數據，您可以使用`Rc::make_mut` 來克隆並獲得要更改的數據的可變引用。\n\n這在 `Component::changed` 中帶來了更多好處，可以確定 prop 變更是否需要元件重新渲染。這是因為可以比較指標位址（即資料儲存在機器記憶體中的位置）而不是資料的值；如果兩個指標指向相同的數據，則它們指向的資料的值必須相同。請注意，反之可能不成立！即使兩個指標位址不同，底層資料仍可能相同 - 在這種情況下，您應該比較底層資料。\n\n要進行此比較，您需要使用 `Rc::ptr_eq` 而不僅使用 `PartialEq`（在使用相等運算子 `==` 比較資料時自動使用）。 Rust 文件有關於 `Rc::ptr_eq` 的[更多細節](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\n這種最佳化對於不實作 `Copy` 的資料類型最有用。如果您可以廉價地複製數據，則沒有必要將其放在智慧指標後面。對於可能是資料密集的結構，如 `Vec`、`HashMap` 和 `String`，使用智慧指標可能會帶來效能改進。\n\n如果數值從不被子元件更新，則此最佳化效果最佳，如果父元件很少更新，則效果更佳。這使得 `Rc<_>` 是在純元件中包裝屬性值的一個不錯的選擇。\n\n但是，必須注意，除非您需要在子元件中自己克隆數據，否則這種最佳化不僅是無用的，而且還增加了不必要的引用計數成本。 Yew 中的 props 已經是引用計數的，內部不會發生資料克隆。\n\n## 渲染函數\n\n出於程式碼可讀性的原因，將 `html!` 的部分重複程式碼遷移到專門分割出來的函數中通常是有意義的。這不僅使您的程式碼更易讀，減少了程式碼縮進，而且還鼓勵良好的設計模式——特別是圍繞構建可組合應用程序，這些函數可以在多個地方調用，從而減少程式碼量。\n\n## 純組件\n\n純組件是不會改變其狀態的元件，只顯示內容並將訊息傳播到普通的可變組件。它們與視圖函數的不同之處在於，它們可以在`html!` 巨集中使用元件語法（`<SomePureComponent />`）而不是表達式語法（`{some_view_function()}`），並且根據其實現，它們可以被記憶化（這意味著一旦調用函數，其值就會被“保存”，因此如果多次使用相同的參數調用它，則不必重新計算其值，只需從第一個函數調用返回保存的值）- 防止相同的props 重新渲染。 Yew 在內部比較 props，因此僅在 props 更改時重新渲染 UI。\n\n## 使用工作區減少編譯時間\n\nYew 的最大缺點是編譯所需的時間很長。編譯專案所需的時間似乎與傳遞給 `html!` 巨集的程式碼數量有關。對於較小的項目，這似乎不是什麼問題，但對於較大的應用程序，將程式碼拆分到多個 crate 中以最小化編譯器為應用程式所做的工作量是有意義的。\n\n一種可能的方法是使您的主 crate 處理路由/頁面選擇，然後為每個頁面建立一個不同的 crate，其中每個頁面可以是不同的元件或只是產生 `Html` 的大函數。儲存在包含應用程式不同部分的 crate 之間的程式碼可以儲存在專案依賴的單獨 crate 中。在最理想的情況下，您從每次編譯時重新建置所有程式碼到僅重新建置主 crate 和一個頁面 crate。在最壞的情況下，如果您在「common」 crate 中編輯了某些內容，您將回到起點：編譯依賴於該常用共享 crate 的所有程式碼，這可能是其他所有內容。\n\n如果您的主crate 太重，或者您想快速迭代一個深度巢狀的頁面（例如。在另一個頁面上渲染的頁面），您可以使用範例crate 建立主頁面的簡化實現，並額外渲染您正在處理的組件。\n\n## 減少二進位檔案大小\n\n- 優化 Rust 程式碼\n- `cargo.toml`（定義發布設定檔）\n- 使用 `wasm-opt` 最佳化 wasm 程式碼\n\n**注意：有關減小二進位檔案大小的更多信息，請參閱[Rust Wasm 手冊](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code -size)。 **\n\n### Cargo.toml\n\n可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用設定來配置發佈建置為更小。\n\n```toml, title=Cargo.toml\n[profile.release]\n# 讓二進位檔案尺寸更小些\npanic = 'abort'\n# 優化整個程式碼庫（優化更好，但建置速度也會更慢）\ncodegen-units = 1\n# 優化尺寸（更激進的做法）\nopt-level = 'z'\n# 優化尺寸\n# opt-level = 's'\n# 使用程式整體分析時進行連結時優化\nlto = true\n```\n\n### 開發版 Cargo 配置\n\n您還可以從 Rust 和 cargo 的實驗性開發版功能中獲得額外的好處。若要使用 `trunk` 的開發版工具鏈，請設定 `RUSTUP_TOOLCHAIN=\"nightly\"` 環境變數。然後，您可以在 `.cargo/config.toml` 中配置不穩定的 rustc 功能。請參考[不穩定功能]的文檔，特別是關於[`build-std`]和[`build-std-features`]的部分，以了解配置。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# 需要 rust-src 組件。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不穩定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n開發版 Rust 編譯器可能包含錯誤，例如[這個例子](https://github.com/yewstack/yew/issues/2696)，需要偶爾注意和調整。請謹慎使用這些實驗性選項。\n:::\n\n### wasm-opt\n\n此外，可以最佳化 `wasm` 程式碼的大小。\n\nRust Wasm 手冊中有關於減少 Wasm 二進位檔案大小的部分：[縮小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用 `wasm-pack`，預設會最佳化發佈建置中的 `wasm` 程式碼\n- 直接在 `wasm` 檔案上使用 `wasm-opt`\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 在 yew/examples/ 中 'minimal' 範例的建置大小\n\n注意：`wasm-pack` 結合了 Rust 和 Wasm 程式碼的最佳化。在此範例中，`wasm-bindgen` 未經任何 Rust 大小最佳化。\n\n| 工具鏈                      | 大小  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## 進一步閱讀\n\n- [Rust 手冊中關於智慧型指標的章節](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm 手冊中關於減小二進位檔案大小的資訊](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust 設定檔的文件](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen 專案](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/portals.mdx",
    "content": "---\ntitle: '傳送門 (Portals)'\ndescription: '將內容渲染到 DOM 樹外的節點'\n---\n\n## 什麼是 Portal？\n\n傳送門 (Portal) 提供了一種將子元素渲染到父元件的 DOM 層次結構以外的 DOM 節點的方法。 `yew::create_portal(child, host)` 傳回一個 `Html` 值，它將 `child` 渲染為 `host` 元素的子元素，而不是在其父元件的層次結構下。\n\n## 用法\n\n傳送門的典型用途包括模態對話框和懸停卡片，以及更多技術應用，例如控制元素的[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API /Element/shadowRoot) 的內容，將樣式表附加到周圍文檔的`<head>` 中，以及在`<svg>` 的中央`<defs>` 元素中收集引用的元素。\n\n請注意，`yew::create_portal` 是一個低階建置區塊。庫應該使用它來實現更高級的 API，然後應用程式可以使用這些 API。例如，這裡是一個簡單的模態對話框，它將其 `children` 渲染到 `yew` 以外的元素中，該元素由 `id=\"modal_host\"` 標識。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## 事件處理\n\n傳送門內部元素上發出的事件遵循虛擬 DOM 冒泡。也就是說，如果傳送門被渲染為元素的子元素，那麼該元素上的事件監聽器將捕捉從傳送門內部分發出的事件，即使傳送門將其內容渲染在實際 DOM 中的不相關位置。\n\n這使開發人員無需關心他們使用的組件是使用傳送門實現的還是沒有使用傳送門實現的。無論如何，其子元素上觸發的事件都會冒泡。\n\n已知問題是，從傳送門到 **關閉** 的 shadow root 的事件將被分發兩次，一次針對 shadow root 內部的元素，一次針對宿主元素本身。請記住，**打開** 的 shadow root 可以正常工作。如果這影響到您，請隨時提交錯誤報告。\n\n## 進一步閱讀\n\n- [傳送門範例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: '服務端渲染'\ndescription: '在服務端渲染 Yew 元件。 '\n---\n\n# 服務端渲染 (Server-Side Rendering)\n\n預設情況下，Yew 元件在客戶端渲染。當使用者造訪一個網站時，伺服器會傳送一個骨架 HTML 文件，不包含任何實際內容，以及一個 WebAssembly 套件給瀏覽器。所有內容都由 WebAssembly 套件在客戶端渲染。這被稱為客戶端渲染。\n\n這種方法對於大多數網站來說都是有效的，但有一些注意事項：\n\n1. 使用者在整個 WebAssembly 套件下載並完成初始渲染之前將看不到任何內容。這可能會導致在緩慢的網路上用戶體驗不佳。\n2. 有些搜尋引擎不支援動態渲染的網頁內容，而那些支援的搜尋引擎通常會將動態網站排名較低。\n\n為了解決這些問題，我們可以在服務端渲染我們的網站。\n\n## 工作原理\n\nYew 提供了一個 `ServerRenderer` 來在服務端渲染頁面。\n\n要在服務端渲染Yew 元件，您可以使用`ServerRenderer::<App>::new()` 建立一個渲染器，並呼叫`renderer.render().await` 將`<App />` 渲染為一個`String`。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// 我們在使用 `flavor = \"current_thread\"` 以確保這個範例可以在 CI 中的 WASM 環境運作,\n// 如果你希望使用多執行緒的話，可以使用預設的 `#[tokio::main]` 宏\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // 列印: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## 組件生命週期\n\n與客戶端渲染不同，元件的生命週期在服務端渲染時會有所不同。\n\n在元件成功第一次渲染為 `Html` 之前，除了 `use_effect` (和 `use_effect_with`) 之外的所有鉤子都會正常運作。\n\n:::caution 瀏覽器介面不可用！\n\n瀏覽器相關的接口，如 `web_sys`，在元件在服務端渲染時是不可用的。如果您嘗試使用它們，您的應用程式將會崩潰。您應該將需要這部分邏輯隔離在 `use_effect` 或 `use_effect_with` 中，因為在服務端渲染時它們無法也不應執行。\n\n:::\n\n:::danger 結構化組件\n\n儘管可以在服務端渲染時使用結構化元件，但是在客戶端安全邏輯（如函數元件的`use_effect` 鉤子）和生命週期事件之間沒有明確的邊界，並且生命週期事件的呼叫順序與客戶端不同。\n\n此外，結構化元件將繼續接受訊息，直到所有子元件都被渲染並呼叫了 `destroy` 方法。開發人員需要確保不會將可能傳遞給元件的訊息連結到呼叫瀏覽器介面的邏輯。\n\n在設計支援服務端渲染的應用程式時，請盡量使用函數元件，除非您有充分的理由不這樣做。\n\n:::\n\n## 服務端渲染期間的資料獲取\n\n資料取得是服務端渲染和水合（hydration）期間的困難之一。\n\n在傳統做法中，當一個元件渲染時，它會立即可用（輸出一個虛擬 DOM 以進行渲染）。當元件不需要取得任何資料時，這種方式是有效的。但是如果元件在渲染時想要取得一些資料會發生什麼事呢？\n\n過去，Yew 沒有機制來檢測組件是否仍在取得資料。資料擷取用戶端負責實作一個解決方案，以偵測在初始渲染期間請求了什麼，並在請求完成後觸發第二次渲染。伺服器會重複這個過程，直到在回傳回應之前沒有在渲染期間添加更多的掛起請求。\n\n這不僅浪費了CPU 資源，因為重複渲染元件，而且資料用戶端還需要提供一種方法，在水合過程中使在服務端獲取的資料可用，以確保初始渲染返回的虛擬DOM 與服務端渲染的DOM樹一致，這可能很難實現。\n\nYew 採用了不同的方法，透過 `<Suspense />` 來解決這個問題。\n\n`<Suspense />` 是一個特殊的元件，當在客戶端使用時，它提供了一種在元件獲取資料（掛起）時顯示一個回退UI 的方法，並在資料獲取完成後恢復到正常UI。\n\n當應用程式在服務端渲染時，Yew 會等待元件不再掛起，然後將其序列化到字串緩衝區中。\n\n在水合過程中，`<Suspense />` 組件中的元素保持未水合狀態，直到所有子組件不再掛起。\n\n透過這種方法，開發人員可以輕鬆建立一個準備好進行服務端渲染的、與客戶端無關的應用程序，並進行資料擷取。\n\n## 渲染 `<head>` 標籤\n\nSSR 中的一個常見需求是渲染動態 `<head>` 內容（例如 `<title>`、`<meta>`），使爬蟲和社群預覽在首次載入時能看到正確的中繼資料。\n\n`ServerRenderer` 只渲染元件樹（通常對應文件的 body 部分），無法存取 `<head>`。因此，head 標籤必須**在伺服器端、Yew 之外**產生，並在傳送給客戶端之前拼接到 HTML 範本中。\n\n[`ssr_router` 範例](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) 展示了這個模式：伺服器從請求 URL 識別路由，產生適當的 `<title>` 和 `<meta>` 標籤，並將它們注入到 Trunk 產生的 `index.html` 的 `</head>` 之前。\n\n:::info\n\n如需完全相容 SSR 的第三方解決方案，請使用 [Bounce 的 `<Helmet/>` 元件](https://docs.rs/bounce/latest/bounce/helmet/index.html)。\n\n:::\n\n## SSR 水合（SSR Hydration）\n\n水合是將 Yew 應用程式連接到服務端產生的 HTML 檔案的過程。預設情況下，`ServerRender` 會列印可水合的 HTML 字串，其中包含額外的資訊以便於水合。當呼叫 `Renderer::hydrate` 方法時，Yew 不會從頭開始渲染，而是將應用程式產生的虛擬 DOM 與伺服器渲染器產生的 HTML 字串進行協調。\n\n:::caution\n\n要成功對由 `ServerRenderer` 建立的 HTML 標記進行水合，用戶端必須產生一個虛擬 DOM 佈局，它與用於 SSR 的佈局完全匹配，包括不包含任何元素的元件。如果您有任何只在一個實作中有用的元件，您可能想要使用 `PhantomComponent` 來填入額外元件的位置。\n:::\n\n:::warning\n\n只有在瀏覽器初始渲染 SSR 輸出（靜態 HTML）後，真實 DOM 與預期 DOM 相符時，水合才能成功。如果您的 HTML 不符合規範，水合可能會失敗。瀏覽器可能會更改不正確的 HTML 的 DOM 結構，導致實際 DOM 與預期 DOM 不同。例如，[如果您有一個沒有`<tbody>` 的`<table>`，瀏覽器可能會向DOM 添加一個`<tbody>`](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## 水合期間的組件生命週期\n\n在水合期間，元件在創建後安排了 2 次連續的渲染。任何效果都是在第二次渲染完成後調用的。確保您的元件的渲染函數沒有副作用是很重要的。它不應該改變任何狀態或觸發額外的渲染。如果您的元件目前改變狀態或觸發額外的渲染，請將它們移到 `use_effect` 鉤子中。\n\n在水合過程中，可以使用結構化元件進行服務端渲染，視圖函數將在渲染函數之前被調用多次。直到呼叫渲染函數之前，DOM 被認為是未連接的，您應該防止在呼叫 `rendered()` 方法之前存取渲染節點。\n\n## 範例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // 對 body 元素下的所有內容進行水合，並移除可能有的任何尾隨元素。\n    renderer.hydrate();\n}\n```\n\n範例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n範例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## 單線程模式\n\nYew 支援以單一執行緒進行服務端渲染，透過 `yew::LocalServerRenderer`。這種模式適用於像 WASI 這樣的單執行緒環境。\n\n```rust\n// 使用 `wasm32-wasip1` 或 `wasm32-wasip2` 目標建置。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n範例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n如果您使用 `wasm32-unknown-unknown` 目標建立 SSR 應用程序，您可以使用 `not_browser_env` 功能標誌來停用 Yew 內部對特定於瀏覽器的 API 的存取。這在像 Cloudflare Worker 這樣的無伺服器平台上非常有用。\n:::\n\n:::caution\n\n服務端渲染目前是實驗性的。如果您發現了一個 bug，[請在 GitHub 回饋](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回呼函數 (Callbacks)'\n---\n\n## 回呼函數 (Callbacks)\n\n回調函數是用於在 Yew 中與服務、代理和父元件進行通訊的。在內部，它們的類型只是 `Fn` 包裝在 `Rc` 中，以允許它們被克隆。\n\n它們有一個 `emit` 函數，該函數以其 `<IN>` 類型作為參數，並將其轉換為其目標期望的訊息。如果父元件中的回呼函數作為 props 提供給子元件，子元件可以在其 `update` 生命週期鉤子中呼叫回呼函數的 `emit` 函數，以將訊息傳回其父元件。在 `html!` 巨集中作為 props 提供的閉包或函數會自動轉換為回呼函數。\n\n一個簡單的回呼函數的使用可能如下所示：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\n這個函數傳遞給 `callback` 必須永遠帶有一個參數。例如，`onclick` 處理程序需要一個接受 `MouseEvent` 類型參數的函數。然後處理程序可以決定應該發送什麼類型的消息給組件。這個訊息無條件地被安排在下一個更新循環中。\n\n如果你需要一個回呼函數，它可能不需要引起更新，請使用 `batch_callback`。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 相關範例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高階組件'\n---\n\n在某些情況下，結構組件不直接支援某些功能（例如 Suspense），或使用某些功能需要大量的樣板程式碼（例如 Context）。\n\n在這些情況下，建議建立高階組件的函數組件。\n\n## 高階組件定義\n\n高階元件是不添加任何新 HTML 的元件，只是包裝其他元件以提供額外功能。\n\n### 範例\n\n對 Context (上下文) 掛鉤並將其傳遞給結構組件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '簡介'\ndescription: 'Yew 中的元件'\n---\n\n## 什麼是元件？\n\n組件是 Yew 的構建塊。它們管理內部狀態並可以將元素渲染到 DOM 中。透過為類型實作 `Component` trait 來建立元件。\n\n## 編寫元件標記\n\nYew 使用虛擬 DOM 將元素渲染到 DOM 中。虛擬 DOM 樹可以透過使用 `html!` 巨集來建構。 `html!` 使用的語法類似 HTML，但並不相同。規則也更嚴格。它還提供了條件渲染和使用迭代器渲染清單等超能力。\n\n:::info\n[了解更多關於 `html!` 宏，如何使用它以及它的語法](concepts/html/introduction.mdx)\n:::\n\n## 將資料傳遞給元件\n\nYew 元件使用 _props_ 在父元件和子元件之間通訊。父元件可以將任何資料作為 props 傳遞給其子元件。 Props 類似於 HTML 屬性，但可以將任何 Rust 類型作為 props 傳遞。\n\n:::info\n[了解更多關於 props 的內容](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n對於除了父/子通信之外的其他通信，請使用 [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命週期'\ndescription: '元件及其生命週期鉤子'\n---\n\n`Component` trait 有許多方法需要實作；Yew 會在元件的生命週期的不同階段呼叫這些方法。\n\n## 生命週期\n\n:::important 改進文檔\n`為文件做貢獻：` [新增自訂生命週期的組件範例](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命週期方法\n\n### Create\n\n當元件被建立時，它會從其父元件接收屬性，並儲存在傳遞給 `create` 方法的 `Context<Self>` 中。這些屬性可以用來初始化元件的狀態，而 \"link\" 可以用來註冊回呼或傳送訊息給元件。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具體實現\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法可讓您描述元件應該如何呈現到 DOM 中。使用Rust 函數編寫類似HTML 的程式碼可能會變得非常混亂，因此Yew 提供了一個名為`html!` 的宏，用於聲明HTML 和SVG 節點（以及將屬性和事件監聽器附加到它們）以及一種方便的方法來渲染子元件。這個宏在某種程度上類似於 React 的 JSX（除了程式語言的差異）。一個不同之處是 Yew 提供了一種類似 Svelte 的屬性的簡寫語法，其中您可以只寫 `{onclick}`，而不用寫 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n就使用上的說明，請查看 [html! 指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 元件生命週期方法在 `view` 被調用並且 Yew 已經將結果渲染到 DOM 中後調用，但在瀏覽器刷新頁面之前。當您想要執行只能在元件渲染元素後完成的操作時，此方法非常有用。還有一個名為 `first_render` 的參數，可以用來確定此函數是在第一次渲染時調用，還是在後續渲染時調用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n請注意，此生命週期方法不需要實現，並且預設不會執行任何操作。\n:::\n\n### Update\n\n與組件的通訊主要透過訊息進行，這些訊息由 `update` 生命週期方法處理。這允許元件根據訊息更新自身，並確定是否需要重新渲染自身。訊息可以由事件監聽器、子元件、Agents、Services 或 Futures 傳送。\n\n下面是 `update` 的實作範例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 重新渲染\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具體實現\n        }\n    }\n\n}\n```\n\n### Changed\n\n元件可能會被其父元件重新渲染。當這種情況發生時，它們可能會接收新的屬性並需要重新渲染。這種設計透過僅更改屬性的值來促進父子組件之間的通訊。當屬性更改時，有一個預設實作會重新渲染元件。\n\n### Destroy\n\n元件從 DOM 卸載後，Yew 會呼叫 `destroy` 生命週期方法；如果您需要在元件被銷毀之前執行清理操作，這是必要的。此方法是可選的，預設不執行任何操作。\n\n### 無限循環\n\n無限循環在 Yew 的生命週期方法中是可能的，但只有在嘗試在每次渲染後更新相同的元件時，當更新也要求重新渲染元件時才會發生。\n\n下面是一個簡單的範例：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // 我們總是請求在任何訊息上重新渲染\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // 無論渲染什麼都不重要\n        Html::default()\n        }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // 請求使用此新訊息更新元件\n        ctx.link().send_message(());\n    }\n}\n```\n\n讓我們看看這裡發生了什麼：\n\n1. 使用 `create` 函數建立元件。\n2. 呼叫 `view` 方法，以便 Yew 知道要渲染到瀏覽器 DOM 中的內容。\n3. 呼叫 `rendered` 方法，使用 `Context` 連結安排更新訊息。\n4. Yew 完成後渲染階段。\n5. Yew 檢查已排程的事件，並看到更新訊息佇列不為空，因此處理訊息。\n6. 呼叫 `update` 方法，回傳 `true` 表示發生了變化，元件需要重新渲染。\n7. 跳回第 2 步。\n\n您仍然可以在 `rendered` 方法中安排更新，這通常是有用的，但是在這樣做時，請考慮您的元件將如何終止此循環。\n\n## 關聯類型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 類型用於在事件發生後向元件發送訊息；例如，您可能希望在使用者點擊按鈕或向下捲動頁面時執行某些操作。因為元件通常需要回應多個事件，所以 `Message` 類型通常是一個枚舉，其中每個變體都是要處理的事件。\n\n在組織程式碼庫時，將 `Message` 類型的定義包含在定義元件的相同模組中是明智的。您可能會發現採用一致的命名約定來命名訊息類型很有幫助。一個選項（儘管不是唯一的選項）是將類型命名為 `ComponentNameMsg`，例如，如果您的元件名為 `Homepage`，則可以將類型命名為 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示從其父元件傳遞給元件的訊息。此類型必須實作 `Properties` trait（通常透過衍生它）並且可以指定某些屬性是必需的還是可選的。在建立和更新元件時使用此類型。在組件的模組中建立一個名為 `Props` 的結構體，並將其用作組件的 `Properties` 類型是一種常見做法。通常將 \"properties\" 縮寫為 \"props\"。由於 props 是從父元件傳遞下來的，因此應用程式的根元件通常具有 `Properties` 類型為 `()`。如果要為根元件指定屬性，請使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多關於屬性的資訊](./properties)\n:::\n\n## 生命週期上下文\n\n所有組件生命週期方法都接受一個上下文物件。此物件提供了對元件作用域的引用，允許向元件發送訊息並傳遞給元件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Props)'\ndescription: '父子元件通訊'\n---\n\n屬性 (Properties) 使子組件和父組件之間能夠進行通訊。每個元件都有一個關聯的屬性類型，用來描述從父元件傳遞下來的內容。理論上，這可以是任何實現了 `Properties` 特性的類型，但實際上，它應該是一個結構體，其中每個字段代表一個屬性。\n\n## 派生宏\n\n無需自己實作 `Properties` 特性，我們可以用 `#[derive(Properties)]` 來自動生成實作。派生 `Properties` 的型別也必須實作 `PartialEq`。\n\n### 欄位屬性\n\n在派生 `Properties` 時，預設情況下所有欄位都是必要的。以下屬性可讓您為屬性提供初始值，除非它們被設定為另一個值。\n\n:::tip\n屬性不會在 Rustdoc 產生的文件中顯示。您的屬性的文檔字串應該說明一個屬性是否是可選的，以及它是否有一個特殊的預設值。\n:::\n\n#### `#[prop_or_default]`\n\n使用欄位類型的預設值使用 `Default` 特性來初始化屬性值。\n\n#### `#[prop_or(value)]`\n\n使用 `value` 來初始化屬性值。 `value` 可以是傳回欄位類型的任何表達式。例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。\n\n#### `#[prop_or_else(function)]`\n\n呼叫 `function` 來初始化屬性值。 `function` 應該有簽章 `FnMut() -> T`，其中 `T` 是欄位類型。\n\n## `PartialEq`\n\n`Properties` 需要實作 `PartialEq`。這樣，Yew 才能比較它們，以便在它們發生變化時呼叫 `changed` 方法。\n\n## 使用 Properties 的效能開銷\n\n內部屬性是基於引用計數的指標儲存的。這意味著只有一個指標被傳遞到元件樹中的屬性，以避免複製整個屬性所帶來的昂貴效能開銷。\n\n:::tip\n使用 `AttrValue`，這是我們提供的自訂屬性值類型，這樣就可以不用 String 或其他類似的需要克隆的類型。\n:::\n\n## 範例\n\n```rust\nuse yew::Properties;\n/// 從 virtual_dom 中導入 AttrValue\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 鏈接必須有一個目標\n    href: AttrValue,\n    /// 還要注意我們使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 鏈接的顏色，默認為 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值為 None，則視圖函數不會指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當視圖函數沒有指定活動時，默認為 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建立屬性。\n\n這個巨集使用與結構體表達式相同的語法，只是您不能使用屬性或基本表達式 (`Foo { ..base }`)。類型路徑可以直接指向屬性 (`path::to::Props`)，也可以指向元件的關聯屬性 (`MyComp::Properties`)。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 鏈接必須有一個目標\n    href: AttrValue,\n    /// 還要注意我們使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 鏈接的顏色，默認為 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值為 None，則視圖函數不會指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當視圖函數沒有指定活動時，默認為 true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// 注意此函數接收 href 和 text 作為 String\n    /// 我們可以使用 `AttrValue::from` 將其轉換為 `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '引用 (Refs)'\ndescription: '實作越界 DOM 存取'\n---\n\n`ref` 關鍵字可以在任何 HTML 元素或元件中使用，以取得附加到該元素的 DOM `Element`。這可以用於在 `view` 生命週期方法之外對 DOM 進行更改。\n\n這對於獲取 canvas 元素或滾動到頁面的不同部分很有用。例如，在元件的 `rendered` 方法中使用 `NodeRef` 允許您在從 `view` 渲染後對 canvas 元素進行繪製呼叫。\n\n文法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 相關範例\n\n- [節點引用](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: '作用域'\ndescription: '元件的作用域'\n---\n\n## 元件的 `Scope<_>` 接口\n\n`Scope` 是透過訊息建立回呼並更新自己的機制。我們透過在傳遞給元件的上下文物件上呼叫 `link()` 來獲得對它的參考。\n\n### `send_message`\n\n這個函數可以向元件發送訊息。訊息由 `update` 方法處理，該方法決定元件是否應重新渲染。\n\n### `send_message_batch`\n\n這個函數可以同時向元件發送多個訊息。這類似於 `send_message`，但是如果任何訊息導致 `update` 方法傳回 `true`，則元件將在處理批次中的所有訊息後重新渲染。\n\n如果給定的參數向量為空，則此函數不執行任何操作。\n\n### `callback`\n\n建立一個回調，當執行時將向元件發送訊息。在內部，它將使用提供的閉包返回的訊息呼叫 `send_message`。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // 建立一個接受一些文本並將其作為 `Msg::Text` 訊息變體發送到元件的回調。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上一行是多餘的冗長，為了更清晰，可以簡化為這樣：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // 將 `Msg::Text(\"Hello World!\")` 發送到元件。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // 在這裡放置 HTML\n        }\n    }\n}\n```\n\n### `batch_callback`\n\n建立一個回調，執行時將向元件發送一批訊息。與 `callback` 的區別在於，傳遞給此方法的閉包不必傳回訊息。相反，閉包可以傳回 `Vec<Msg>` 或 `Option<Msg>`，其中 `Msg` 是元件的訊息類型。\n\n`Vec<Msg>` 被視為一批訊息，並在內部使用 `send_message_batch`。\n\n`Option<Msg>` 在值為 `Some` 時呼叫 `send_message`。如果值為 `None`，則不執行任何操作。這可以用於根據情況，不需要更新的情況。\n\n這是透過使用僅為這些類型實現的 `SendAsMessage` trait 來實現的。您可以為自己的類型實作 `SendAsMessage`，這樣可以在 `batch_callback` 中使用它們。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/agents.mdx",
    "content": "---\ntitle: '代理 (Agents)'\ndescription: \"Yew's 的代理系統\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n代理程式 (Agents) 是一種將任務卸載到 Web Workers 的方式。\n\n為了使代理程式能夠並發運行，Yew 使用了 [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命週期\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## 代理程式的類型\n\n### 範圍\n\n- 公開 - 在任何給定時間，公共代理的實例最多只有一個。橋樑將在 Web Worker 中產生或連接到已經產生的代理程式。當沒有橋樑連接到此代理時，代理將消失。\n\n- 私有 - 為每個新的橋樑在 Web Worker 中產生一個新的代理程式。這對於將與瀏覽器通訊的共享但獨立的行為從元件中移出是很好的。當連接的橋樑被丟棄時，代理將消失。\n\n- 全域 \\(WIP\\)\n\n## 代理與元件之間的通信\n\n### 通信橋 (Bridges)\n\n通訊橋 (bridge) 是一個元件和代理程式之間的通訊通道。它允許元件向代理發送訊息，並接收來自代理的訊息。\n\n`use_bridge` 鉤子也提供了在函數元件中建立橋樑的功能。\n\n### 派發器 (Dispatchers)\n\n派發器 (Dispatchers) 允許元件和代理程式之間進行單向通信，元件以此方式向代理程式發送訊息。\n\n## 開銷\n\n代理程式使用 Web Workers（即私有和公開）。它們在發送和接收訊息時會產生序列化開銷。代理程式使用 [bincode](https://github.com/bincode-org/bincode) 與其他執行緒通信，因此成本比僅呼叫函數要高得多。\n\n## 進一步閱讀\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 範例展示了元件如何向代理程式傳送訊息並接收來自代理程式的訊息。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: '使用 classes! 巨集處理 CSS 類別'\ndescription: '用一個方便的巨集來處理 CSS 類別'\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew 並沒有提供原生的 CSS-in-Rust 解決方案，但透過提供程式設計方式與 HTML `class` 屬性互動的方式來輔助樣式。\n\n## `classes!` 巨集\n\n`classes!` 巨集和相關的 `Classes` 結構簡化了 HTML 類別的使用：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n更多 CSS 相關的內容請參考[此文檔](../../more/css)。\n\n## 內聯樣式\n\n目前 Yew 並沒有提供特殊的輔助工具來處理透過 `style` 屬性指定的內聯樣式，但你可以像處理其他 HTML 屬性一樣處理它：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n更多 CSS 相關的內容請參考[此文檔](../../more/css)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: '使用 html! 巨集處理 HTML'\ndescription: '這是 HTML，但不完全是！ '\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n你可以使用 `html!` 巨集來寫類似 HTML 的表達式。 Yew 會在背景轉換為表達 DOM 的 Rust 程式碼。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\n類似於格式化表達式，您可以透過使用花括號將周圍上下文的值嵌入 HTML 中：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n使用 `html!` 有一個重要的規則 - 您只能傳回一個包裝節點。為了渲染多個元素的列表，`html!` 允許使用空標籤（Fragments）。空標籤是沒有名稱的標籤，它們本身不會產生 HTML 元素。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// 錯誤：只允許一個根 HTML 元素\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修正：使用 HTML 空標籤包裹\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n更多關於 Yew 和 HTML 的內容請參考[更多 HTML](concepts/html/introduction.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'Javascript 與 Rust'\ndescription: '在 Rust 中使用 JavaScript'\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew 在一個地方集中了一個可重用的 UI 部分可能需要的所有內容 - rust 文件，同時也在必要時保持底層技術的可訪問性。\n\n截至今天，WebAssembly 對於 DOM 互動還不完全支援。這意味著即使在 Yew 中，我們有時也依賴呼叫 JavaScript。接下來是涉及的庫的概述。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一個在 JavaScript 和 Rust 函數之間建立呼叫橋樑的函式庫和工具。\n\n我們強烈建議您查看他們的[文件](https://wasm-bindgen.github.io/wasm-bindgen/)和我們的[快速指南](./wasm-bindgen.mdx)。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 為 Web API 提供了綁定，並允許我們以一種經過 Rust 處理和安全的方式編寫 JavaScript 程式碼。\n\n範例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n再次強調，我們強烈建議您查看他們的[文件](https://wasm-bindgen.github.io/wasm-bindgen/)和我們的[快速指南](./web-sys.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一個在 JavaScript 和 Rust 函數之間建立呼叫橋樑的函式庫和工具。它是由 [Rust 和 WebAssembly 工作小組](https://rustwasm.github.io/) 使用 Rust 建構的。\n\nYew 使用 `wasm-bindgen` 透過一些 crate 與瀏覽器進行互動：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\n本節將從更抽象的層次探討這些 crate，以便更容易理解和使用 Yew 中的 `wasm-bindgen` API。要了解有關 `wasm-bindgen` 及其相關 crate 的更深入指南，請查看 [`wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/)。\n\n有關上述 crate 的文檔，請查看 [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html)。\n\n:::tip\n使用 `wasm-bindgen` doc.rs 搜尋來尋找已使用 `wasm-bindgen` 匯入的瀏覽器 API 和 JavaScript 類型。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\n這個 crate 為上面的其他 crate 提供了許多構建塊。在本節中，我們只會涵蓋 `wasm-bindgen` crate 的兩個主要領域，即巨集和一些您會一遍又一遍看到的類型/特性。\n\n### `#[wasm_bindgen]` macro\n\n`#[wasm_bindgen]` 巨集提供了 Rust 和 JavaScript 之間的接口，提供了一個在兩者之間進行轉換的系統。使用這個巨集更為高級，除非您要使用外部 JavaScript 函式庫，否則不應該使用它。 `js-sys` 和 `web-sys` crate 為內建 JavaScript 類型和瀏覽器 API 提供了 `wasm-bindgen` 定義。\n\n讓我們透過一個簡單的範例來使用`#[wasm-bindgen]` 巨集來匯入一些特定版本的[`console.log`](https://developer.mozilla.org/en-US/docs/Web/ API/Console/log) 函數。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// 首先讓我們手動綁定 `console.log`，而不使用 `web_sys` 的幫助。\n// 在這裡，我們手動寫 `#[wasm_bindgen]` 註解，我們程式的正確性取決於這些註解的正確性！\n#[wasm_bindgen]\nextern \"C\" {\n    // 在這裡使用 `js_namespace` 來綁定 `console.log(..)` 而不是只有 `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` 是多態的，所以我們可以使用多個簽章綁定它。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 多個參數也是可以的！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// 使用導入的函數！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_這個範例是基於 [1.2 使用 console.log 的 `wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) 改編的。 _\n\n### 模擬繼承\n\n在 JavaScript 類別之間的繼承是 JavaScript 語言的核心特性，DOM（文件物件模型）是圍繞它設計的。當使用 `wasm-bindgen` 匯入類型時，您也可以新增描述它們繼承關係的屬性。\n\n在Rust 中，這種繼承關係使用[`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) 和[`AsRef`](https://doc. rust-lang.org/std/convert/trait.AsRef.html) 特性來表示。這裡舉個例子可能會有所幫助；假設您有三種類型 `A`、`B` 和 `C`，其中 `C` 擴展了 `B`，而 `B` 又擴展了 `A`。\n\n在匯入這些類型時，`#[wasm-bindgen]` 巨集將按照下列方式實作 `Deref` 和 `AsRef` 特性：\n\n- `C` 可以 `Deref` 到 `B`\n- `B` 可以 `Deref` 到 `A`\n- `C` 可以被 `AsRef` 到 `B`\n- `C` 和 `B` 都可以被 `AsRef` 到 `A`\n\n這些實作允許您在 `C` 的實例上呼叫 `A` 的方法，並將 `C` 用作 `&B` 或 `&A`。\n\n需要注意的是，使用`#[wasm-bindgen]` 導入的每種類型都有相同的根類型，您可以將其視為上面範例中的`A`，這種類型是[`JsValue`](#jsvalue)，下面有它的部分。\n\n_[`wasm-bindgen` 指引中的 extends 部分](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\n這是 JavaScript 擁有的物件的表示，這是 `wasm-bindgen` 的根捕獲類型。任何來自`wasm-bindgen` 的型別都是`JsValue`，這是因為JavaScript 沒有強型別系統，因此接受變數`x` 的任何函數都不定義其型別，因此`x` 可以是有效的JavaScript 值；因此`JsValue`。如果您正在使用接受 `JsValue` 的導入函數或類型，那麼任何導入的值在技術上都是有效的。\n\n`JsValue` 可以被函數接受，但該函數可能仍然只接受某些類型，這可能會導致panic - 因此在使用原始`wasm-bindgen` API 時，請檢查導入的JavaScript 的文檔，以確定是否會在該值不是某種類型時引發異常（panic）。\n\n_[`JsValue` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)。 _\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust 有一個強型別系統，而 JavaScript…沒有😞。為了讓 Rust 保持這些強型別但仍然方便，WebAssembly 工作小組提出了一個非常巧妙的特性 `JsCast`。它的工作是幫助您從一個JavaScript \"類型\" 轉換到另一個\"類型\"，這聽起來很模糊，但它意味著如果您有一個類型，您知道它是另一個類型，那麼您可以使用`JsCast ` 的函數從一個型別跳到另一個型別。當使用 `web-sys`、`wasm_bindgen`、`js-sys` 時，了解這個很好的特性 - 您會注意到許多類型將從這些 crate 中實作 `JsCast`。\n\n`JsCast` 提供了轉換的檢查和不檢查方法- 因此在運行時，如果您不確定某個物件是什麼類型，您可以嘗試將其轉換，這將返回可能的失敗類型，如[`Option`] (https://doc.rust-lang.org/std/option/enum.Option.html) 和[`Result`](https://doc.rust-lang.org/std/result/enum.Result. html)。\n\n一個常見的例子是在 [`web-sys`](./web-sys.mdx) 中，當您嘗試取得事件的目標時。您可能知道目標元素是什麼，但[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API 總是會回傳一個[` Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)。\n您需要將其轉換為元素類型，以便呼叫其方法。\n\n```rust\n// 需要先導入這個 Trait\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // 也許目標是一個選擇元素？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 做點別的\n        return;\n    }\n\n    // 如果它能確定不是一個選擇元素，那麼我可以肯定它是一個輸入元素！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) 方法是一個檢查的轉換，回傳一個`Option<&T>`，這表示如果轉換失敗，則可以再次使用原始類型，因此傳回`None`。 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 方法將消耗`self`，這是Rust 中`into` 方法的約定，傳回的類型是`Result<T, Self>`。如果轉換失敗，則原始的 `Self` 值將在 `Err` 中傳回。您可以再試一次或對原始類型進行其他操作。\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 類型提供了一種將 Rust 閉包傳遞到 JavaScript 的方法，出於健全性原因，傳遞給 JavaScript 的閉包必須具有 `'static` 生命週期。\n\n這種類型是一個“句柄”，這意味著每當它被丟棄時，它將使其引用的 JS 閉包無效。在 `Closure` 被丟棄後，對 JS 中閉包的任何使用都會引發異常。\n\n當您使用接受型別[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 的`js-sys` 或`web-sys` API 時，通常會使用`Closure`。在[Events](../html/events.mdx) 頁面的[Using `Closure` 部分](../html/events.mdx#using-closure-verbose) 中可以找到Yew 中使用`Closure` 的範例。\n\n_[`Closure` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` crate 提供了 JavaScript 標準內建物件的綁定/導入，包括它們的方法和屬性。\n\n這不包括任何 Web API，因為這是 [`web-sys`](./web-sys.mdx) 的作用！\n\n_[`js-sys` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` crate 提供了一個橋樑，用於將JavaScript Promise 類型作為Rust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 進行處理，並包含將Rust Future 轉換為JavaScript Promise 的實用程式。當在 Rust（wasm）中處理非同步或其他阻塞工作時，這可能很有用，並提供了與 JavaScript 事件和 JavaScript I/O 原語互動的能力。\n\n目前這個 crate 中有三個主要介面：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   一個使用[`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) 建構的類型，然後可以用作`Future<Output=Result<JsValue, JsValue >>`。如果 `Promise` 被解析，這個 `Future` 將解析為 `Ok`，如果 `Promise` 被拒絕，則解析為 `Err`，分別包含 `Promise` 的解析或拒絕值。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   將 Rust `Future<Output=Result<JsValue, JsValue>>` 轉換為 JavaScript `Promise`。未來的結果將轉換為 JavaScript 中的已解析或已拒絕 `Promise`。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   在目前執行緒上產生一個 `Future<Output = ()>`。這是在 Rust 中運行 Future 的最佳方法，而不是將其發送到 JavaScript。\n\n_[`wasm-bindgen-futures` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` 將是 Yew 中 `wasm-bindgen-futures` crate 中最常用的部分，因為這有助於使用具有非同步 API 的函式庫。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // 列印 \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew 還在某些 API 中添加了對 futures 的支持，最值得注意的是您可以創建一個接受 `async` 區塊的 `callback_future` - 這在內部使用了 `spawn_local`。\n\n_[`spawn_local` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys crate 為 Web API 提供綁定。 '\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 為 Web API 提供綁定。這是從瀏覽器 WebIDL 產生的，這就是為什麼有些名稱如此之長，有些類型如此模糊的原因。\n\n## `web-sys` 中的特性 (features)\n\n`web-sys` crate 中啟用了所有特性可能會為 Wasm 應用程式增加很多冗餘。為了解決這個問題，大多數類型都是透過啟用 features 進行控制的，這樣你只需要包含你的應用程式所需的類型。 Yew 啟用了 `web-sys` 的幾個特性，並在其公共 API 中公開了一些類型。你通常需要自行將 `web-sys` 新增為依賴項。\n\n## `web-sys` 中的繼承\n\n在[模擬繼承](./wasm-bindgen.mdx#simulating-inheritance)部分，你可以了解到 Rust 通常提供了一種模擬 JavaScript 中繼承的方法。這在 `web-sys` 中非常重要，因為了解一個類型上有哪些方法意味著了解它的繼承。\n\n這一部分將查看一個特定的元素，並使用Rust 呼叫[`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) 列出其繼承，直到該值為[`JsValue`](./wasm-bindgen.mdx#jsvalue)。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement 是 HTML 中的 <textarea>。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意我們現在已經從 web-sys 類型轉移到內建的 JavaScript 類型，\n    // 這些類型在 js-sys crate 中。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意我們現在已經從 js-sys 類型轉移到 wasm-bindgen crate 中的根 JsValue。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // 這樣使用 deref 意味著我們必須手動遍歷繼承樹。\n    // 但是，您可以在 HtmlTextAreaElement 類型上呼叫 JsValue 方法。\n    assert!(!text_area.is_string());\n\n    // 這個空函數只是為了證明我們可以將 HtmlTextAreaElement 作為 &EventTarget 傳遞。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // 編譯器將沿著 deref 鏈向下走，以符合這裡的類型。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 實作可讓您將 HtmlTextAreaElement 視為 &EventTarget。\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[`wasm-bindgen` 指引中的 `web-sys` 繼承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)_\n\n## `NodeRef` 中的 `Node`\n\nYew 使用 [`NodeRef`](concepts/function-components/node-refs.mdx) 來提供一種方式來保留由 [`html!`](concepts/html/introduction.mdx) 巨集所建立的 `Node` 的引用。 `NodeRef` 中的 `Node` 指的是 [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html)。 `NodeRef::get` 方法將傳回一個 `Option<Node>` 值，但是，在 Yew 中，大多數情況下，您希望將此值轉換為特定元素，以便使用其特定方法。如果存在，可以使用 [`JsCast`](./wasm-bindgen.mdx#JsCast) 對 `Node` 值進行轉換，但是Yew 提供了 `NodeRef::cast` 方法來執行此轉換，以方便使用，因此您不一定需要為 `JsCast` 特性包含 `wasm-bindgen` 依賴項。\n\n下面的兩個程式碼區塊本質上是相同的，第一個使用 `NodeRef::cast`，第二個使用 [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 在 `NodeRef::get` 傳回的 `web_sys::Node` 上。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // 在這裡處理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // 在這裡處理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript 重構為 Rust 的範例\n\n這一節展示如何將與 Web API 互動的 JavaScript 程式碼範例重寫為 Rust 中的 `web-sys`。\n\n### JavaScript 範例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e 為滑鼠事件對象\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 元素内的 x 位置。\n    var y = e.clientY - rect.top // 元素内的 y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### 用 `web-sys` 重寫的範例\n\n只使用 `web-sys`，上面的 JavaScript 範例可以這樣實作：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 需要啟用所有我們想要使用的 web-sys 功能！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 我們現在需要保存 `mousemove` 閉包，以便在事件觸發時閉包仍然在記憶體中。\n```\n\n這個版本更加冗長，但你可能會注意到其中的一部分是由於失敗類型提醒我們，一些函數呼叫有必須保持的不變量，否則將在 Rust 中引發 panic。另一個冗長的部分是呼叫 `JsCast` 來將不同類型轉換為特定類型，以便呼叫其特定方法。\n\n### 用 Yew 重寫的範例\n\n在Yew 中，您將主要建立 [`Callback`](concepts/function-components/callbacks.mdx) 以在 [`html!`](concepts/html/introduction.mdx) 巨集中使用，因此範例將使用這種方法，而不是完全複製上面的方法：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# 我們需要啟用 `DomRect` 特性以使用 `get_bounding_client_rect` 方法。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 補充依賴庫\n\n`web-sys` 是 Web API 的原始綁定，囙此在 Rust 中會有一些痛苦，因為它並不是為 Rust 或甚至强類型系統設計的，這就是社區 crate 提供了對 `web-sys` 的抽象，以提供更符合 Rust 習慣的 API。\n\n_[補充依賴庫清單]（/community/external-libs）_\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/contexts.mdx",
    "content": "---\ntitle: '上下文 (Contexts)'\nsidebar_label: Contexts\ndescription: '使用上下文傳遞深度嵌套資料'\n---\n\n通常，資料是透過 props 從父元件傳遞到子元件。\n但是，如果必須透過中間的許多元件傳遞它們，或者如果應用程式中的許多元件需要相同的訊息，傳遞 props 可能會變得冗長和煩人。\n上下文解決了這個問題，允許父元件使資料可用於其下方樹中的任何元件，無論多深，而無需透過 props 傳遞它們。\n\n## 使用 props 的問題：\"Prop Drilling\"\n\n傳遞 [props](./function-components/properties.mdx) 是從父元件直接傳遞資料到子元件的好方法。\n但是，當需要透過深層嵌套的組件樹傳遞資料或多個組件共享相同的資料時，傳遞 props 變得繁瑣。\n一種常見的資料共享解決方案是將資料提升到一個共同的祖先，並使子元件將其作為 props 接收。\n然而，這可能導致 props 必須通過多個元件才能到達需要它的元件。\n這種情況稱為 \"Prop Drilling\"。\n\n考慮以下範例，它透過 props 傳遞主題：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App 根節點\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n我們透過 `Navbar` 傳遞主題設定，以便它可以到達 `Title` 和 `NavButton`。\n如果 `Title` 和 `NavButton` 這些需要存取主題的元件可以直接存取主題而不必透過 prop 傳遞，那就更好了。\n上下文解決了這個問題，允許父元件將資料（在這種情況下是主題）傳遞給其子元件。\n\n## 使用上下文\n\n### 步驟 1：提供上下文\n\n需要一個上下文提供者來消費上下文。 `ContextProvider<T>`，其中 `T` 是用作提供者的上下文結構體。\n`T` 必須實作 `Clone` 和 `PartialEq`。 `ContextProvider` 是其子元件將擁有上下文的元件。\n當上下文變更時，子元件會重新渲染。一個結構體用來定義要傳遞的資料。 `ContextProvider` 可以這樣使用：\n\n```rust\nuse yew::prelude::*;\n\n/// App 主題\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// 主組件\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` 是 `Rc<UseStateHandle<Theme>>` 類型，而我們需要 `Theme`\n        // 所以我們對它進行解引用。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // 這裡的每個子元件及其子元件都將存取此上下文。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// 工具栏\n/// 此组件可以访问上下文。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// 放置在 `Toolbar` 中的按鈕\n/// 由於此元件是元件樹中 `ThemeContextProvider` 的子元件，它也可以存取上下文。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### 步驟 2：使用上下文\n\n#### 函數元件\n\n`use_context` 鉤子用於在函數元件中使用上下文。\n請參閱 [use_context 文件](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) 以了解更多資訊。\n\n#### 結構體組件\n\n我們有兩種選擇在結構體組件中使用上下文：\n\n- [高階元件](../advanced-topics/struct-components/hoc)：高階函數元件將使用上下文並將資料傳遞給需要它的結構體元件。\n- 直接在結構體組件中使用上下文。請參閱 [結構體組件作​​為消費者的範例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## 使用場景\n\n通常，如果某些資料需要在樹的不同部分的遠端元件中使用，上下文可能會對你有所幫助。\n以下是一些這樣的例子：\n\n- **主題**：你可以在應用程式的頂部放置一個上下文來保存你的應用程式主題，並使用它來調整視覺外觀，如上例所示。\n- **目前使用者帳戶**：在許多情況下，元件需要知道目前登入的使用者。你可以使用上下文將目前使用者物件提供給元件。\n\n### 使用上下文前的考慮\n\n上下文非常容易使用，這也使得它們非常容易被誤用/過度使用。\n僅僅因為你可以使用上下文將 props 共享給多個層級深的元件，並不意味著你應該這樣做。\n\n例如，你可以提取一個元件並將該元件作為子元件傳遞給另一個元件。例如，\n你可能有一個 `Layout` 元件，它將 `articles` 作為 prop 並傳遞給 `ArticleList` 元件。\n你應該重構 `Layout` 元件，使其接受子元件作為 props 並顯示 `<Layout> <ArticleList {articles} /> </Layout>`。\n\n## 修改子元件的上下文值\n\n由於 Rust 的所有權規則，上下文不能有一個可以被子元件呼叫的 `&mut self` 方法。\n要修改上下文的值，我們必須將其與 reducer 結合使用。這可以透過使用\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) 鉤子完成。\n\n[上下文範例](https://github.com/yewstack/yew/tree/master/examples/contexts) 示範了使用上下文的可變上下文\n\n## 進一步閱讀\n\n- [上下文範例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: '回调 (Callbacks)'\n---\n\n回調函數用於在元件樹中向上傳遞訊息，以及在事件處理期間與其他元件（如代理或 DOM）進行通訊。在內部，回調函數的類型只是一個 `Fn`，並且被包裝在 `Rc` 中，以便它們可以被廉價地複製。\n\n如果您想手動呼叫回調函數，可以使用 `emit` 函數。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // 呼叫回調函數\n// web_sys::console::log_1(&result.into()); // 若取消註釋，將列印 \"Bye Bob\"\n```\n\n## 將回呼函數當作屬性傳遞\n\n在 yew 中的一個常見模式是建立一個回呼函數，並將其作為屬性傳遞給子元件。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 然後提供屬性 (Props)\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // 如果取消註釋，這裡會列印文本\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM 事件和回呼函數\n\n回調函數也用於連接到 DOM 事件。\n\n例如，這裡我們定義了一個回呼函數，當使用者點擊按鈕時將會呼叫：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // 如果取消註釋，這裡會列印文本\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子元素 (Children)'\n---\n\n`Children` 是一種特殊的屬性類型，可讓您接收嵌套的 `Html`，就像 html 子元素一樣提供。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` 鍵很重要！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // 可以靠這種方式轉送子元素\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/communication.mdx",
    "content": "---\ntitle: '組件之間的通訊'\n---\n\n## 父元件向子元件發送訊息\n\n將資料作為 [props](./properties) 傳遞，這會導致重新渲染，這是向子元件傳遞訊息的方法。\n\n## 子元件向父元件發送訊息\n\n透過 props 傳遞一個回調，子元件在事件上可以呼叫。 [範例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/generics.mdx",
    "content": "---\ntitle: '泛型元件'\ndescription: '函數元件的 #[component] 屬性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 屬性也適用於用於建立泛型元件的泛型函數。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// 之後可以這樣使用\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// 或者\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: '自訂 Hooks'\n---\n\n## 定義自訂 Hooks\n\n元件的有狀態邏輯可以透過建立自訂 Hooks 來提取為可重複使用的函數。\n\n假設我們希望建立一個事件監聽器，監聽 `window` 物件上的事件。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\n這段程式碼有一個問題：邏輯無法被另一個元件重複使用。如果我們建立另一個監聽不同事件的元件，而不是複製程式碼，我們可以將邏輯移入自訂 hook。\n\n我們將首先建立一個名為 `use_event` 的新函數。 `use_` 前綴表示函數是一個 hook。此函數將接受一個事件目標、一個事件類型和一個回呼。所有 hook 必須在其函數定義上標記為 `#[hook]`。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\n這個簡單的 hook 可以透過組合內建 hook 來創建。在本例中，我們將使用 `use_effect_with` hook，因此當 hook 參數變更時，可以重新建立事件監聽器。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\n儘管這種方法在幾乎所有情況下都有效，但它無法用於編寫像我們已經使用的預定義 hook 那樣的基本 hook。\n\n查看 [docs.rs](https://docs.rs/yew) 上的文件以及 `hooks` 目錄，查看預先定義 hook 的實作。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks 是一類能夠儲存狀態和執行副作用的函數。\n\nYew 提供了一些預先定義的 hooks。您也可以創建自己的 hooks，或發現許多[社區製作的 hooks](/community/awesome#hooks)。\n\n## Hooks 規則\n\n1. 每個 Hook 函數的名稱必須以 `use_` 開頭\n2. Hooks 只能在下列位置使用：\n\n- 函數/ Hook 的頂層\n- 函數/ Hook 內的區塊，只要它沒有被分支\n- 函數/ Hook 內頂層 `if` 表達式的條件\n- 函數/ Hook 內頂層 `match` 表達式的選擇器\n\n3. 每次渲染時，Hooks 必須以相同的順序呼叫。只有在使用 [Suspense](../../suspense.mdx) 時才允許提前返回\n\n這些規則由編譯時或執行時錯誤來執行。\n\n### 預定義 Hooks\n\nYew 提供了以下預定義 Hooks：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\n這些 hooks 的文檔可以在 [Yew API 文件](https://yew-rs-api.web.app/next/yew/functional/)中找到。\n\n### 自訂 Hooks\n\n有些情況下，您可能想要定義自己的 Hooks，以將元件中的可能具有狀態的邏輯封裝到可重複使用的函數中。\n\n## 進一步閱讀\n\n- React 文件中有一個關於 [React hooks](https://reactjs.org/docs/hooks-intro.html) 的部分。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函數組件'\nslug: /concepts/function-components\n---\n\n讓我們重新回顧一下之前的標語：\n\n> Yew 的核心思想是將可重複使用的 UI 部分所需的所有內容集中在一個地方 - Rust 檔案中。\n\n我們將透過引入將定義應用程式的邏輯和呈現行為的概念來完善這個陳述：\"元件\"。\n\n## 什麼是元件？\n\n組件是 Yew 的構建塊。\n\n它們應當：\n\n- 以 [Props](./properties.mdx) 的形式接受參數\n- 可以擁有自己的狀態\n- 計算使用者可見的 HTML 片段（DOM）\n\n## Yew 組件的兩種風味\n\n您目前正在閱讀有關函數元件的內容 - 這是在開始使用 Yew 時以及在編寫簡單的呈現邏輯時編寫元件的建議方式。\n\n還有一種更高級但不太容易訪問的編寫組件的方式 - [結構組件](advanced-topics/struct-components/introduction.mdx)。它們允許非常詳細的控制，儘管大多數情況下您不需要那麼詳細的控制。\n\n## 建立函數元件\n\n若要建立函數元件，請將 `#[component]` 屬性加入到一個函式中。依照慣例，函數的名稱採用 PascalCase，與 `html!` 巨集中的普通 html 元素形成對比。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 然後在其他地方，您可以在 `html!` 中使用元件\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## 組件內部發生了什麼\n\n在渲染時，Yew 將建立這些元件的虛擬樹。它將調用每個（函數）元件的 view 函數來計算 DOM 的虛擬版本（VDOM），您作為庫用戶將其視為 `Html` 類型。對於上面的範例，這將如下所示：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n當需要更新時，Yew 將再次呼叫 view 函數，並將新的虛擬 DOM 與其先前的版本進行協調，並僅將新的/更改的/必要的部分傳 播到實際的 DOM。這就是我們所說的 **渲染**。\n\n:::note\n\n實際上，`Html` 只是 `VNode` 的別名 - 一個虛擬節點。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: '節點引用'\ndescription: 'DOM 外部存取'\n---\n\n`ref` 屬性可以用於將 `NodeRef` 附加到 HTML 元素上。在回呼中，您可以取得 `ref` 附加到的 DOM `Element`。這可以用於在 `view` 生命週期方法之外對 DOM 進行更改，檢索 `<input>` 的值以及透過 javascript API 直接與 DOM 互動。\n\n這對於獲取 canvas 元素或滾動到頁面的不同部分很有用。\n\n:::caution\n不要手動修改 Yew 渲染的 DOM 樹。如果不確定，請將 `NodeRef` 視為唯讀存取。\n:::\n\n## 進一步閱讀\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` 範例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Properties)'\ndescription: '父子元件通訊'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n屬性 (Properties) 通常被簡寫為 \"Props\"。\n\n:::\n\n屬性 (Properties) 是元件的參數，Yew 可以監視這些參數。\n\n在元件的屬性中使用一個類型之前，它必須實作 `Properties` trait。\n\n## 響應性\n\n在重新渲染時，Yew 在協調虛擬 DOM 時檢查屬性是否已更改，以了解是否需要重新渲染巢狀元件。這樣，Yew 可以被認為是一個非常具有響應性的框架，因為來自父組件的變更總是會向下傳播，視圖永遠不會與來自屬性/狀態的資料不同步。\n\n:::tip\n\n如果您尚未完成 [教學](../../tutorial)，請嘗試並自行測試這種回應性！\n\n:::\n\n## 派生宏\n\nYew 提供了一個衍生宏，可以輕鬆地在結構體上實作 `Properties` trait。\n\n您衍生 `Properties` 的型別也必須實作 `PartialEq`，以便 Yew 可以進行資料比較。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函數元件中使用\n\n屬性 `#[component]` 允許在函式參數中選擇性地接收 Props。要提供它們，可以透過 `html!` 巨集中的屬性進行賦值。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// 然後提供屬性\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 沒有屬性需要提供\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生巨集欄位屬性\n\n在派生 `Properties` 時，預設情況下所有欄位都是必要的。\n\n以下屬性可讓您為屬性提供預設值，當父元件沒有設定它們時將使用這些預設值。\n\n:::tip\n屬性在 Rustdoc 產生的文檔中是不可見的。您的屬性的文檔字串應該提到一個屬性是否是可選的，以及它是否有一個特殊的預設值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` trait 的欄位類型的預設值初始化屬性值。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 這樣使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 來初始化屬性值。 `value` 可以是傳回欄位類型的任何表達式。\n\n例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。當屬性被建構時，表達式會被評估，且沒有給出明確的值。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// 這樣使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n呼叫 `function` 來初始化屬性值。 `function` 應該有 `FnMut() -> T` 簽名，其中 `T` 是欄位類型。當沒有為該屬性給出明確的值時，將呼叫該函數。\n這個函數在屬性被建構時被呼叫。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// 使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的效能開銷\n\n內部屬性是以引用計數的智慧型指標傳遞的。這意味著只有一個共享指標被傳遞到元件樹中的屬性，這樣就能節約克隆整個屬性的高昂成本。\n\n:::tip\n`AttrValue` 是我們用於屬性值的自訂類型，這樣就不用將它們定義為 String 或其他類似克隆成本高昂的類型了。\n:::\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建立屬性。\n\n這個巨集使用與結構表達式相同的語法，只是您不能使用屬性或基本表達式 (`Foo { ..base }`)。類型路徑可以直接指向屬性 (`path::to::Props`)，也可以指向元件的關聯屬性 (`MyComp::Properties`)。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 注意我們不需要指定 name 屬性\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自動產生屬性 (yew-autoprops)\n\n為了簡化您的開發流程，您也可以使用巨集 `#[autoprops]`（來自 `yew-autoprops` 套件）自動產生 `Properties` 結構體。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] 巨集必須出現在 #[component] 之前，順序很重要\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 結構體 \"GreetingsProps\" 將會自動產生。\n//\n// `is_loading` 將作為值傳遞給元件，而 `message` 和 `name` 將使用引用，因為定義中有一個前導的 `&`。\n```\n\n## 評估順序\n\n屬性依照指定的順序進行評估，如下例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n雖然幾乎任何 Rust 類型都可以作為屬性傳遞，但有一些反模式應該避免。這些包括但不限於：\n\n1. 使用 `String` 類型而不是 `AttrValue`。 <br />\n   **為什麼不好？ ** `String` 克隆成本高。當屬性值與鉤子和回調一起使用時，通常需要克隆。 `AttrValue` 是一個引用計數的字串 (`Rc<str>`) 或一個 `&'static str`，因此非常便宜克隆。 <br />\n   **注意**：`AttrValue` 在內部是來自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看該包以了解更多資訊。\n2. 使用內部可變性。 <br />\n   **為什麼不好？ ** 內部可變性（例如 `RefCell`、`Mutex` 等）應該 _通常_ 避免使用。它可能會導致重新渲染問題（Yew 不知道狀態何時發生了變化），因此您可能需要手動強制重新渲染。就像所有事物一樣，它有其用武之地。請謹慎使用。\n3. 使用 `Vec<T>` 型別而不是 `IArray<T>`。 <br />\n   **為什麼不好？ ** `Vec<T>`，就像 `String` 一樣，克隆成本也很高。 `IArray<T>` 是一個引用計數的切片 (`Rc<[T]>`) 或一個 `&'static [T]`，因此非常便宜克隆。 <br />\n   **注意**：`IArray` 可以從 [implicit-clone](https://crates.io/crates/implicit-clone) 匯入。查看該包以了解更多資訊。\n4. 您發覺可能的新內容。您是否遇到了一個希望早點了解清楚的邊緣情況？請隨時建立一個問題或向本文檔提供修復的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一個實驗性包，可讓您根據函數的參數動態建立 Props 結構體。如果屬性結構體永遠不會被重複使用，這可能會很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '純組件'\n---\n\n每個函數元件都是一個[純](https://zh.wikipedia.org/zh-hk/%E7%BA%AF%E5%87%BD%E6%95%B0)函數，它接受一個屬性物件並傳回一個`Html` 物件。純函數是指在給定相同輸入時，總是會傳回相同輸出的函數。\n\n這個例子是一個純組件。對於給定的屬性 `is_loading`，它總是傳回相同的 `Html`，沒有任何副作用。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n如果您有一個內部純元件，它不使用 hooks 和其他元件機制，您通常可以將其編寫為傳回 `Html` 的普通函數，從而避免 Yew 運行元件生命週期相關的一些開銷。使用 [表達式語法](concepts/html/literals-and-expressions.mdx#expressions) 在 `html!` 中渲染它們。\n:::\n\n## 非純組件\n\n您可能想知道，如果元件不使用任何全域變量，那麼它是否可以是不“純”的，因為它只是在每次渲染時調用的固定函數。\n這就是下一個主題 - [hooks](./hooks) 的用武之地。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/state.mdx",
    "content": "---\ntitle: '狀態'\n---\n\n## 如何儲存狀態的一般視圖\n\n這個表格可以作為一個指南，幫助您決定哪種狀態儲存類型最適合您的用例：\n\n| Hook             | 類型                       | 何時渲染?                        | 作用域                   |\n| ---------------- | -------------------------- | -------------------------------- | ------------------------ |\n| [use_state]      | `T`                        | 被設定一個值                     | 組件內部實例             |\n| [use_state_eq]   | `T: PartialEq`             | 被設定一個不同的值               | 組件內部實例             |\n| [use_reducer]    | `T: Reducible`             | 被呼叫歸納                       | 組件內部實例             |\n| [use_reducer_eq] | `T: Reducible + PartialEq` | 被呼叫歸納，歸納後的值與之前不同 | 組件內部實例             |\n| [use_memo]       | `Deps -> T`                | 依賴項發生變化                   | 組件內部實例             |\n| [use_callback]   | `Deps -> Callback<E>`      | 依賴項發生變化                   | 組件內部實例             |\n| [use_mut_ref]    | `T`                        | -                                | 組件內部實例             |\n| 全域靜態常數     | `T`                        | -                                | 全域，任何位置都可以使用 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/classes.mdx",
    "content": "---\ntitle: '類別'\ndescription: '一個方便的巨集來處理類別'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 類別\n\n`Classes` 結構體可以用來處理 HTML 類別。\n\n將字串推送到集合時，`Classes` 確保每個類別都有一個元素，即使單一字串可能包含多個類別。\n\n`Classes` 也可以透過使用 `Extend`（即 `classes1.extend(classes2)`）或 `push()`（即 `classes1.push(classes2)`）來合併。任何實作 `Into<Classes>` 的類型都可以推送到現有的 `Classes` 上。\n\n`classes!` 是一個方便的巨集，它建立一個單一的 `Classes`。它的輸入接受一個逗號分隔的表達式清單。唯一的要求是每個表達式都實作了 `Into<Classes>`。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 接受類別的元件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/components.mdx",
    "content": "---\ntitle: '組件'\ndescription: '使用元件層次結構建立複雜的佈局'\n---\n\n## 基礎\n\n元件可以在 `html!` 巨集中使用：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // 沒有屬性\n        <MyComponent />\n\n        // 使用屬性\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // 一次提供所有屬性\n        <MyComponentWithProps ..props.clone() />\n\n        // 使用變數中的屬性，並覆寫特定值\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## 嵌套\n\n如果組件在其 `Properties` 中有一個 `children` 字段，它可以接受子組件/元素\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` 巨集允許您使用`..props` 語法傳遞一個基本表達式，而不是單獨指定每個屬性，類似於Rust 的[函數式更新語法](https://doc.rust-lang.org /stable/reference/expressions/struct-expr.html#functional-update-syntax)。\n這個基本表達式必須出現在傳遞任何單獨的 props 之後。\n當傳遞一個帶有 `children` 欄位的基本 props 表達式時，`html!` 巨集中傳遞的子元素將覆蓋已經存在於 props 中的子元素。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子元素將覆蓋 props.children\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 相關範例\n\n- [函數化 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [函數化路由](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '條件渲染'\ndescription: '在 html 中有條件地渲染節點！ '\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If 區塊\n\n要有條件地渲染一些標記，我們將其包裝在 `if` 區塊中：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/elements.mdx",
    "content": "---\ntitle: '元素'\ndescription: '支援 HTML 和 SVG 元素'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM 節點\n\n在 Yew 中手動建立或管理 DOM 節點的原因有很多，例如與可能與受管理元件衝突的 JS 庫整合。\n\n使用 `web-sys`，您可以建立 DOM 元素並將其轉換為 `Node` - 然後可以使用 `VRef` 將其用作 `Html` 值：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // 帶記憶能力的函數，只會執行一次\n    let node = use_memo(\n        (),\n        |_| {\n            // 從文件中建立一個 div 元素\n            let div: Element = document().create_element(\"div\").unwrap();\n            // 新增內容、類別等\n            div.set_inner_html(\"Hello, World!\");\n            // 將 Element 轉換為 Node\n            let node: Node = div.into();\n            // 將該 Node 作為 Html 值傳回\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo 回傳的是 Rc 指針，所以我們需要解引用和克隆\n    (*node).clone()\n}\n\n```\n\n## 動態標籤名\n\n在建立高階元件時，您可能會發現自己處於一個標籤名不是靜態的情況。例如，您可能有一個 `Title` 元件，根據等級屬性可以渲染從 `h1` 到 `h6` 的任何內容。而不是使用一個大的匹配表達式，Yew 允許您動態設定標籤名，使用 `@{name}`，其中 `name` 可以是傳回字串的任何表達式。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 邏輯值屬性\n\n一些內容屬性（例如 checked、hidden、required）被稱為邏輯值屬性。在 Yew 中，邏輯值屬性需要設定為布林值：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\n這與以下的 **HTML** 功能上是等價的：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n將邏輯值屬性設為 false 等效於不使用該屬性；可以使用邏輯表達式的值：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\n這與以下 **HTML** 結果等價：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 類似字串的屬性\n\n除了一些邏輯值屬性，您可能會處理許多類似字串的 HTML 屬性，Yew 有幾種選項可以將類似字串的值傳遞給元件。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\n它們都是有效的，**但**我們鼓勵您更傾向於使用 Yew 的自訂 `AttrValue`，特別是如果您需要複製或將它們作為屬性傳遞給另一個元件。\n\n## HTML 元素的可選屬性\n\n大多數 HTML 屬性可以使用可選值（Some(x) 或 None）。這使我們可以在屬性被標記為可選時省略該屬性。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n如果屬性設為 `None`，則該屬性將不會在 DOM 中設定。\n\n## 相關範例\n\n- [內嵌 HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/events.mdx",
    "content": "---\ntitle: '事件'\n---\n\n## 介紹\n\nYew 與 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate 集成，並使用該 crate 中的事件。下面的[表格](#event-types)列出了在 `html!` 巨集中接受的所有 `web-sys` 事件。\n\n您仍然可以為下表中未列出的事件新增 [`Callback`](../function-components/callbacks.mdx)，請參閱[手動事件監聽器](#manual-event-listener)。\n\n## 事件類型\n\n:::tip\n所有的事件類型都在 `yew::events` 下重新匯出。\n使用 `yew::events` 中的類型比手動將 `web-sys` 作為依賴項包含在您的 crate 中更容易確保版本相容性，\n因為您不會使用與 Yew 指定的版本衝突的版本。\n:::\n\n事件監聽器的名稱是在 `html` 巨集中新增事件 `Callback` 時預期的名稱：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\n事件名稱是監聽器名稱去掉 \"on\" 前綴，因此 `onclick` 事件監聽器監聽 `click` 事件。查看本頁末的[完整事件清單](#available-events)及其類型。\n\n## 事件捕獲 {#event-bubbling}\n\nYew 調度的事件遵循虛擬 DOM 層次結構，向上冒泡到監聽器。目前，僅支援監聽器的冒泡階段。請注意，虛擬 DOM 層次結構通常（但並非總是）與實際 DOM 層次結構相同。在處理[傳送門](../../advanced-topics/portals)和其他更高級技術時，這一區別很重要。對於良好實現的元件，直覺應該是事件從子元件冒泡到父元件。這樣，您在 `html!` 中所寫的層次結構就是事件處理程序觀察到的層次結構。\n\n如果您不想要事件冒泡，可以透過呼叫\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n在啟動應用程式*之前*。這會加快事件處理速度，但某些元件可能會因未收到預期的事件而中斷。請謹慎使用！\n\n## 事件委託\n\n可能會讓人驚訝的是，事件監聽器並不是直接註冊在它們被渲染的元素上。相反，事件是從 Yew 應用的子樹根節點委託的。不過，事件仍然以其原生形式傳遞，並且不會創建任何合成形式。這可能會導致 HTML 監聽器中預期的事件與 Yew 中出現的事件之間的不符。\n\n- [`Event::current_target`] 指向 Yew 子樹根節點，而不是新增監聽器的元素。如果您想存取底層的 `HtmlElement`，請使用 [`NodeRef`](../function-components/node-refs.mdx)。\n- [`Event::event_phase`] 總是 [`Event::CAPTURING_PHASE`]。在內部，事件將表現得像是在冒泡階段，事件傳播將被重播，並且事件會[向上冒泡](#event-bubbling)，即虛擬DOM 中較高的事件監聽器將在較低的事件監聽器之後觸發。目前，Yew 不支援捕獲監聽器。\n\n這也意味著由 Yew 註冊的事件通常會在其他事件監聽器之前觸發。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 具備類型的事件目標\n\n:::caution\n在本節中，**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** 總是指的是事件從其派發的元素。\n\n這**不一定**總是指 `Callback` 所放置的元素。\n:::\n\n在事件 `Callback` 中，您可能想要取得該事件的目標。例如，`change` 事件沒有提供任何訊息，但用於通知某些內容已更改。\n\n在 Yew 中，以正確的類型獲取目標元素可以透過幾種方式完成，我們將在這裡逐一介紹。呼叫事件上的[`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) 傳回一個可選的[ `web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 類型，當您想知道輸入元素的值時，這可能看起來不太有用。\n\n在下面的所有方法中，我們將解決相同的問題，以便清楚地了解方法的不同之處，而不是手邊的問題。\n\n**問題：**\n\n我們在 `<input>` 元素上有一個 `onchange` `Callback`，每次呼叫時，我們希望向元件發送一個[更新](components#update) `Msg`。\n\n我們的 `Msg` 列舉如下：\n\n```rust\npub enum Msg {\n InputValue(String),\n}\n```\n\n### 使用 `JsCast`\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate 有一個有用的trait：[`JsCast`](https://rustwasm.github .io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)，它允許我們在類型之間直接轉換，只要它實現了`JsCast` 就行。我們可以謹慎地轉換，這涉及運行時檢查和處理 `Option` 和 `Result` 的邏輯，或者我們也可以冒險直接強行轉換。\n\n多說無益，看代碼：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# 需要 wasm-bindgen 用於呼叫 JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // 當事件被建立時，目標是未定義的，只有在派發時才會新增目標。\n            let target: Option<EventTarget> = e.target();\n            // 事件可能會冒泡，因此此偵聽器可能會捕獲不是 HtmlInputElement 類型的子元素的事件。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // 你必須了解 target 是 HtmlInputElement，否則呼叫 value 將是未定義行為（UB）。\n        // 在這裡，我們確信這是輸入元素，因此我們可以在不檢查的情況下將其轉換為適當的類型。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` 提供的方法是 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\n和 [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)。\n如你所見，它們允許我們從 `EventTarget` 轉換為 [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html)。\n`dyn_into` 方法是謹慎的，因為它會在運行時檢查類型是否實際為 `HtmlInputElement`，如果不是則返回\n`Err(JsValue)`。 [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n是一個通用類型，將原來的物件回傳給你，以便再次嘗試轉換為別的類型。\n\n這會兒你可能會想，什麼時候可以使用危險版本？在上面的情況下，它是安全的<sup>1</sup>，因為我們將 `Callback` 設定在一個沒有子元素的元素上，所以目標只能是同一個元素。\n\n_<sup>1</sup> 只要牽涉到 JS 領域，就是安全的。 _\n\n### 使用 `TargetCast`\n\n**強烈建議先閱讀 [使用 JsCast](#using-jscast)！ **\n\n:::note\n`TargetCast` 的設計目的是讓新用戶了解 `JsCast` 的行為，但範圍更小，僅涉及事件及其目標。\n\n選用 `TargetCast` 或 `JsCast` 純粹是個人偏好，實際您會發現 `TargetCast` 的實作和 `JsCast` 的功能很相似。\n:::\n\n`TargetCast` trait 是在 `JsCast` 基礎之上建構的，專門用於從事件中取得類型化的事件目標。\n\n`TargetCast` 是 Yew 的一部分，因此無需添加依賴項即可在事件上使用 trait 方法，但它的工作方式與 `JsCast` 非常相似。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // 你必須清楚 target 是 HtmlInputElement，否則呼叫 value 將是未定義行為（UB）。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n如果您已經了解了 `JsCast`，或者了解了這個 trait，您可能會發現 `TargetCast::target_dyn_into` 與 `JsCast::dyn_into` 相似，但專門用於事件的目標。 `TargetCast::target_unchecked_into` 與 `JsCast::unchecked_into` 類似，因此上面關於 `JsCast` 的所有警告都適用於 `TargetCast`。\n\n### 使用 `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) 可以取代查詢給定給 `Callback` 的事件。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n透過 `NodeRef`，你可以忽略事件並使用 `NodeRef::cast` 方法取得一個`Option<HtmlInputElement>` - 這是可選的，因為在設定 `NodeRef` 之前呼叫 `cast`，或者當類型不符時將會回傳 `None`。\n\n你可能會看到，透過使用 `NodeRef`，我們不必將 `String` 傳回狀態，因為我們總是存取 `input_node_ref` - 因此我們可以這樣做：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // 對 value 做點什麼\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\n您選擇哪種方法取決於您的元件和您的偏好，沒有所謂的*推薦*方法。\n\n## 手動事件監聽器\n\n您可能想要監聽 Yew 的 `html` 巨集不支援的事件，請查看[這裡列出的支援的事件](#event-types)。\n\n為了手動為某個元素新增事件監聽器，我們需要藉助 [`NodeRef`](../function-components/node-refs.mdx)，以便在 `use_effect_with` 中使用 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) 和 [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API 新增監聽器。\n\n以下範例將展示如何為虛構的 `custard` 事件新增監聽器。所有不受 yew 支援的事件或自訂事件都可以表示為\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html)。如果您需要存取自訂/不受支援事件的特定方法或字段，可以使用\n[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) 的方法將其轉換為所需的類型。\n\n### 使用 `Closure`（冗長版本）\n\n直接使用 `web-sys` 和 `wasm-bindgen` 的介面可能有點痛苦…所以要有點心理準備（[感謝 `gloo`，有了更簡潔的方法](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 建立您通常會建立的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 對 custard 做點什麼..\n                    });\n\n                    // 從 Box<dyn Fn> 創建一個 Closure - 這必須是 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有關 `Closure` 的更多信息，請參見 [wasm-bindgen 指南](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html)。\n\n### 使用 `gloo`（簡潔版本）\n\n更方便的方法是使用 `gloo`，更具體地說是 [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)，\n它是 `web-sys`、`wasm-bindgen` 的高層抽象實作。\n\n`gloo_events` 提供了 `EventListener` 類型，可以用來建立和儲存事件監聽器。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 建立您通常會建立的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 對 custard 做點什麼..\n                    });\n\n                    // 從 Box<dyn Fn> 創建一個 Closure - 這必須是 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有關 `EventListener` 的更多信息，請參見 [gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html)。\n\n## 可用事件的完整清單 {#available-events}\n\n| 偵聽器名稱                  | `web_sys` 事件類型                                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空標籤 (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 巨集總是需要一個根節點。為了繞過這個限制，您可以使用一個“空標籤”（也稱為“fragments”）。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// 錯誤：只允許一個根 HTML 元素\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: '用於產生 HTML 和 SVG 的過程巨集'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 巨集可讓您聲明性地編寫 HTML 和 SVG 程式碼。它類似於 JSX（一種允許您在 JavaScript 中編寫類似 HTML 的程式碼的擴充）。\n\n**重要提示**\n\n1. `html! {}` 巨集只能接受一個根HTML 節點（您可以透過使用[fragments](./fragments.mdx) 或[iterators](./../html/lists.mdx) 來規避這一點）\n2. 空的 `html! {}` 呼叫是有效的，不會渲染任何內容\n3. 字面量必須永遠用引號引起來並用大括號括起來：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` 巨集會將所有標籤名稱轉換為小寫。若要使用大寫字元（某些SVG 元素所需的字元）請使用[動態標籤名稱](concepts/html/elements.mdx#dynamic-tag-names)：`html! { <@{\"myTag\"}>< /@> }`\n\n:::note\n`html!` 巨集可能會達到編譯器的預設遞歸限制。如果遇到編譯錯誤，請在 crate 根目錄中新增類似 `#![recursion_limit=\"1024\"]` 的屬性以解決問題。\n:::\n\n## 標籤 (Tags) 結構\n\n標籤 (Tags) 是基於 HTML 標籤。元件、元素和清單都基於此標籤語法。\n\n標籤必須或自閉合 `<... />`，或對於每個開始標籤都有一個對應的結束標籤。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 缺少閉合標籤\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 缺少閉合標籤\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n方便起見，通常需要閉合標籤的元素**允許**自閉合。例如，編寫 `html! { <div class=\"placeholder\" /> }` 是有效的。\n:::\n\n建立複雜的巢狀 HTML 和 SVG 佈局還是很容易的：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\n如果您使用 Rust 編譯器的開發者版本編譯 Yew，巨集將警告您可能遇到的一些常見陷阱。當然，您可能需要使用穩定版編譯器（例如，您的組織可能有政策要求這樣做）進行發布構建，但即使您使用的是穩定工具鏈，運行`cargo +nightly check` 也可能會標記一些可以改進HTML 程式碼的方法。\n\n目前，這些 lint 主要與可訪問性相關。如果您有 lint 的想法，請隨時[在此問題中發表意見](https://github.com/yewstack/yew/issues/1334)。\n\n## 指定屬性和屬性\n\n屬性與普通 HTML 中的元素設定方式相同：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n屬性在元素名稱之前用 `~` 指定：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n如果值是一個字面量的話，圍繞值的大括號可以省略。\n\n:::\n\n:::note 什麼是字面量\n\n字面量是 Rust 中所有有效的[字面量表達式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)。請注意，[負數**不是**字面量](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)，因此必須用大括號括起來 `{-6}`。\n\n:::\n\n:::note 元件屬性\n元件屬性以 Rust 物件傳遞，與此處所述的元素參數 (Attributes) / 屬性 (Properties) 不同。\n在[元件屬性](../function-components/properties.mdx)中了解更多。\n:::\n\n### 特殊屬性\n\n有一些特殊屬性不會直接影響 DOM，而是作為 Yew 虛擬 DOM 的指令。目前有兩個這樣的特殊屬性：`ref` 和 `key`。\n\n`ref` 可讓您直接存取和操作底層 DOM 節點。有關更多詳細信息，請參閱 [Refs](../function-components/node-refs.mdx)。\n\n另一方面，`key` 為元素提供了一個唯一標識符，Yew 可以用於最佳化目的。\n\n:::info\n[了解更多相關內容](./html/lists)\n:::\n\n## 條件渲染\n\n可以透過使用 Rust 的條件結構來條件性地渲染標記。目前只支援 `if` 和 `if let`。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n閱讀[條件渲染](./conditional-rendering.mdx)一節以了解更多\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/lists.mdx",
    "content": "---\ntitle: '列表'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 迭代器\n\n從迭代器建立 HTML 有 3 種方法：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` 迴圈\">\n主要方法是使用 for 迴圈，與 Rust 中已有的 for 迴圈相同，但有 2 個關鍵區別：\n1. 與標準 for 迴圈不能傳回任何內容不同，`html!` 中的 for 迴圈會被轉換為節點清單；\n2. 發散運算式，即 `break`、`continue` 在 `html!` 中的 for 迴圈主體內是不允許的。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` 區塊\">\n另一種方法是使用 `for` 關鍵字，這不是原生的 Rust 語法，而是由 HTML 巨集用於輸出顯示迭代器所需的程式碼。\n當迭代器已經計算好，只需要將其傳遞給巨集時，這種方法比第一種更好。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` 方法\">\n\n最後一種方法是在迭代器的最終轉換上呼叫 `collect::<Html>()`，它傳回一個 Yew 可以顯示的清單。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 鍵 (Key) 列表\n\n鍵 (Key) 列表是一個最佳化的列表，其中**所有**子元素都有鍵。\n`key` 是 Yew 提供的一個特殊屬性，它為 HTML 元素或元件提供一個唯一標識符，用於 Yew 內部的最佳化。\n\n:::caution\nKey 只需要在每個清單中是唯一的，與 HTML `id` 的全域唯一性相反。它不應該依賴於列表的順序。\n:::\n\n始終建議為清單新增按鍵 (key)。\n\n可以透過將唯一的 `String`、`str` 或整數傳遞給特殊的 `key` 屬性來新增鍵：\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### 效能優化\n\n我們有一個[帶有鍵 (keys) 的列表範例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)可以讓你測試效能上的改進，這裡有一個簡單的測試流程：\n\n1. 進入[線上示範](https://examples.yew.rs/keyed_list)\n2. 新增 500 個元素\n3. 停用鍵\n4. 反轉列表\n5. 看 \"最後一次渲染花費了 Xms\"（在撰寫本文時，大約為 60ms）\n6. 啟用鍵\n7. 再次反轉列表\n8. 看 \"最後一次渲染花費了 Xms\"（在撰寫本文時，大約為 30ms）\n\n截至撰寫本文時，對於 500 個組件，速度提高了 2 倍。\n\n### 原理解釋\n\n通常，當你迭代時，只需要在每個列表項目上添加一個鍵，資料的順序可能會改變。\n在重新渲染清單時，它用於加速協調過程。\n\n如果沒有鍵，假設你迭代 `[\"bob\", \"sam\", \"rob\"]`，最終得到的 HTML 如下：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n然後在下一次渲染時，如果你的清單更改為 `[\"bob\", \"rob\"]`，Yew 可以刪除 id=\"rob\" 的元素，並將 id=\"sam\" 更新為 id=\"rob\"。\n\n如果你為每個元素添加了一個鍵，初始HTML 將保持不變，但在使用修改後的列表`[\"bob\", \"rob\"]` 進行渲染後，Yew 只會刪除第二個HTML 元素，而其他元素則保持不變，因為它可以使用鍵將它們關聯起來。\n\n如果你遇到了一個從一個元件切換到另一個元件的 bug/\"feature\"，但兩者都有一個 div 作為最高渲染元素。\nYew 在這些情況下會重複使用已渲染的 HTML div 作為最佳化。\n如果你需要該 div 被重新建立而不是被重複使用，那麼你可以添加不同的鍵，它們將不會被重複使用。\n\n## 進一步閱讀\n\n- [TodoMVC 範例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [帶有按鍵 (keys) 的清單範例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [路由範例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: '字面量與表達式'\n---\n\n## 字面量\n\n如果表達式解析為實現了 `Display` 的類型，它們將被轉換為字串並插入到DOM 中作為[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 節點。\n\n:::note\n字串字面量會建立 `Text` 節點，瀏覽器將其視為字串。因此，即使表達式包含 `<script>` 標籤，您也不會遇到 XSS 等安全性問題，除非您將表達式包裝在 `<script>` 區塊中。\n:::\n\n所有顯示文字都必須用 `{}` 區塊括起來，因為文字被視為表達式。這是 Yew 與普通 HTML 語法最大的偏差。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 表達式\n\n您可以使用 `{}` 區塊在 HTML 中插入表達式，只要它們解析為 `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常將這些表達式提取到函數或閉包中以優化可讀性是有意義的：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/router.mdx",
    "content": "---\ntitle: '路由 (Router)'\ndescription: 'Yew 的官方路由庫'\n---\n\n單頁應用程式 (SPA) 中的路由器處理根據 URL 顯示不同的頁面。與點擊連結時請求不同的遠端資源的預設行為不同，路由器會在本機設定 URL 以指向應用程式中的有效路由。然後，路由器偵測到此變更並決定要渲染的內容。\n\nYew 在 `yew-router` crate 中提供了路由器支援。要開始使用它，請將依賴項新增至您的 `Cargo.toml` 檔案中。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n所需的工具均在 `yew_router::prelude` 模組中提供，\n\n## 用法\n\n最開始，你需要定義一個 `Route`。\n\n路由由一個 `enum` 定義，它衍生自 `Routable`。這個枚舉必須實作 `Clone + PartialEq`。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` 與 `<Switch />` 元件配對，後者會找到與瀏覽器目前 URL 相符的路徑變體，並將其傳遞給 `render` 回呼。然後回調決定要渲染的內容。如果沒有路徑匹配，路由器會導航到帶有 `not_found` 屬性的路徑。如果沒有指定路由，則不會渲染任何內容，並且會在控制台中記錄一條訊息，說明沒有符合的路由。\n\nyew-router 的大多數元件，特別是 `<Link />` 和 `<Switch />`，必須是某個 Router 元件（例如 `<BrowserRouter />`）的（深層）子元素。通常在應用程式中只需要一個 Router，通常由最頂層的 `<App />` 元件立即渲染。 Router 註冊了一個上下文，這是 Links 和 Switches 功能所需的。下面提供了一個範例。\n\n:::caution\n在瀏覽器環境中使用 `yew-router` 時，強烈建議使用 `<BrowserRouter />`。您可以在 [API 參考](https://docs.rs/yew-router/) 中找到其他路由器類型。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### 路徑段\n\n路由還可以使用動態和命名通配符段從路由中提取資訊。然後，您可以在 `<Switch />` 內存取貼文的 id，並透過屬性將其轉發到對應的元件。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n您也可以使用普通的 `Post` 變體，而不是 `Post {id: String}`。例如，當 `Post` 與另一個路由器一起渲染時，該欄位可能是多餘的，因為另一個路由器可以匹配並處理路徑。有關詳細信息，請參閱下面的[嵌套路由器](#nested-router)部分。\n:::\n\n請注意，欄位必須實作 `Clone + PartialEq` 作為 `Route` 枚舉的一部分。它們還必須實作 `std::fmt::Display` 和 `std::str::FromStr` 以進行序列化和反序列化。整數、浮點數和字串等原始類型已經滿足這些要求。\n\n當路徑的形式匹配，但反序列化失敗（根據 `FromStr`）。路由器將認為路由不匹配，並嘗試渲染未找到的路由（或者如果未指定未找到的路由，則渲染空白頁面）。\n\n參考以下範例：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// 切換函數會渲染 News 和 id。這裡省略了。\n```\n\n當段超過 255 時，`u8::from_str()` 將失敗並傳回 `ParseIntError`，路由器將認為路由不符。\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\n有關路由語法和如何綁定參數的更多信息，請查看 [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params)。\n\n### 位置 (Location)\n\n路由器透過上下文提供了一個通用的 `Location` 結構，可以用來存取路由資訊。它們可以透過鉤子或 `ctx.link()` 上的便捷函數來檢索。\n\n### 導航\n\n`yew_router` 提供了一些工具來處理導航。\n\n#### 連結\n\n`<Link />` 渲染為`<a>` 元素，`onclick` 事件處理程序將呼叫 [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)，並將目標頁面推送到歷史記錄中並渲染所需的頁面，這正是單頁應用程式所期望的行為。普通錨元素的預設 `onclick` 會重新載入頁面。\n\n`<Link />` 元件也會將其子元素傳遞給 `<a>` 元素。可以將其視為應用程式內路由的 `<a/>` 替代品。不同之處在於你需要提供 `to` 屬性而不是 `href`。範例用法如下：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n結構體變數也可以正常運作：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### 導航接口\n\n導航器 API 為函數元件和結構元件提供。它們使回調能夠更改路由。可以在任一情況下取得 `Navigator` 實例以操作路由。\n\n##### 函數式元件\n\n對於函數元件，當底層導覽器提供者變更時，`use_navigator` 鉤子會重新渲染元件。\n以下是實現一個按鈕的範例，該按鈕在點擊時導航到 `Home` 路由。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\n這裡的範例使用了 `Callback::from`。如果目標路由可以與元件所在的路由相同，或只是為了安全起見，請使用普通的回呼。例如，考慮在每個頁面上都有一個徽標按鈕，點擊該按鈕會返回主頁。在主頁上點擊該按鈕兩次會導致程式碼崩潰，因為第二次點擊會推送一個相同的 Home 路由，並且 `use_navigator` 鉤子不會觸發重新渲染。\n:::\n\n如果您想要取代目前的位置而不是將新位置推到堆疊上，請使用 `navigator.replace()` 而不是 `navigator.push()`。\n\n您可能會注意到 `navigator` 必須移動到回呼中，因此不能再次用於其他回呼。幸運的是，`navigator` 實作了 `Clone`，例如，以下是如何為不同的路由設定多個按鈕：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 結構體組件\n\n對於結構體元件，可以透過 `ctx.link().navigator()` API 取得 `Navigator` 實例。其餘部分與函數組件的情況相同。以下是一個渲染單一按鈕的視圖函數範例。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### 重定向\n\n`yew-router` 在 prelude 中也提供了一個 `<Redirect />` 元件。它可以用於實現與導航器 API 類似的效果。該元件接受一個 `to` 屬性作為目標路由。當渲染 `<Redirect/>` 時，使用者將被重定向到屬性中指定的路由。以下是一個範例：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // 建立對 `use_user` 的鉤子\n    let user = match use_user() {\n        Some(user) => user,\n        // 當使用者為 `None` 時重定向到登入頁面\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 實際頁面內容\n}\n```\n\n:::tip 如何選擇 `Redirect` 或 `Navigator`\nNavigator API 是在回呼中操作路由的唯一方法。\n而 `<Redirect />` 可以作為元件中的回傳值使用。您可能還想在其他非元件上下文中使用 `<Redirect />`，例如在[嵌套路由器](#nested-router)的 switch 函數中。\n:::\n\n### 監聽變化\n\n#### 函數式元件\n\n您可以使用 `use_location` 和 `use_route` 鉤子。當提供的值發生變化時，您的元件將重新渲染。\n\n#### 結構體組件\n\n為了回應路由變化，您可以將回呼閉包傳遞給 `ctx.link()` 的 `add_location_listener()` 方法。\n\n:::note\n一旦位置監聽器被刪除，它將被取消註冊。請確保將句柄儲存在元件狀態中。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // 處理事件\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` 和 `ctx.link().route::<R>()` 也可以用於一次性擷取位置和路由。\n\n### 查詢參數\n\n#### 在導航時指定查詢參數\n\n為了在導覽到新路由時指定查詢參數，可以使用 `navigator.push_with_query` 或 `navigator.replace_with_query` 函數。它使用 `serde` 將參數序列化為 URL 的查詢字串，因此任何實作了 `Serialize` 的類型都可以傳遞。最簡單的形式是包含字串對的 `HashMap`。\n\n#### 取得目前路由的查詢參數\n\n`location.query` 用來取得查詢參數。它使用 `serde` 從 URL 的查詢字串中反序列化參數。\n\n## 嵌套路由器\n\n當應用程式變得更大時，嵌套路由器可能會很有用。考慮以下路由器結構：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\n嵌套的 `SettingsRouter` 處理所有以 `/settings` 開頭的 URL。此外，它會將未符合的 URL 重新導向到主 `NotFound` 路由。因此，`/settings/gibberish` 將會重新導向到 `/404`。\n\n:::caution\n\n請注意，該介面仍在開發中，這樣寫的方式尚未最終確定\n\n:::\n\n可以使用以下程式碼實作：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### 基底路徑 (Basename)\n\n可以使用 `yew-router` 定義基底路徑 (Basename)。\n基底路徑是所有路由的公共前綴。導航器 API 和 `<Switch />` 元件都支援基底路徑設定。所有推送的路由都會加上基底路徑前綴，所有的 switch 都會在嘗試將路徑解析為 `Routable` 之前去掉基底路徑。\n\n如果沒有為 Router 元件提供基底路徑屬性，它將使用 HTML 檔案中 `<base />` 元素的 href 屬性，並在 HTML 檔案中沒有 `<base />` 元素時回退到 `/`。\n\n## 相關範例\n\n- [路由](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## 介面參考\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/suspense.mdx",
    "content": "---\ntitle: '佔位標籤 (Suspense)'\ndescription: '用於資料獲取的佔位標籤'\n---\n\n佔位標籤 (Suspense) 是一種在等待任務完成前暫停元件渲染的方式，同時顯示一個回退（佔位符）UI。\n\n它可以用於從伺服器取得數據，等待代理完成任務，或執行其他後台非同步任務。\n\n在佔位標籤出現之前，資料擷取通常發生在元件渲染之後（渲染時取得）或之前（取得後渲染）。\n\n### 邊渲染，邊下載\n\n佔位標籤 (Suspense) 提供了一種新的方法，允許元件在渲染過程中啟動資料請求。當元件啟動資料請求時，渲染過程將被暫停，並顯示一個回退 UI，直到請求完成。\n\n建議使用鉤子 (Hook) 來使用佔位標籤。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n在上面的範例中，`use_user` 鉤子將在載入使用者資訊時暫停元件渲染，並在載入 `user` 之前顯示 `Loading...` 佔位符。\n\n要定義一個暫停元件渲染的鉤子，它需要傳回一個 `SuspensionResult<T>`。當元件需要暫停時，鉤子應該傳回一個 `Err(Suspension)`，使用者應該使用 `?` 解包它，這樣它將被轉換為 `Html`。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 當使用者載入完成時，我們將其作為 Ok(user) 傳回。\n        Some(m) => Ok(m),\n        None => {\n            // 當使用者仍在載入時，我們建立一個 `Suspension`\n            // 並在資料載入完成時呼叫 `SuspensionHandle::resume`，\n            // 元件將自動重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### 關於實作暫停鉤子 (Hook) 的注意事項\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) 傳回 2 個值：暫停上下文本身和一個暫停句柄。後者負責在何時重新渲染暫停的元件，它提供了 2 種可互換的方法：\n\n1. 呼叫其 [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) 方法。\n2. 丟棄句柄。\n\n:::danger\n\n暫停句柄必須儲存直到更新元件的時候，也就是使用新接收的資料；否則，暫停的元件將進入無限重新渲染循環，從而影響效能。\n在上面的範例中，暫停句柄會透過移至閉包中並傳遞給 `on_load_user_complete` 來儲存。\n當虛擬使用者載入時，將呼叫閉包，從而呼叫 `handle.resume()` 並重新渲染與暫停上下文相關的元件。\n\n:::\n\n# 完整範例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 如果用戶已加載，則將其作為 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 當使用者仍在載入時，我們建立一個 `Suspension`\n            // 並在資料載入完成時呼叫 `SuspensionHandle::resume`，\n            // 元件將自動重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 在結構體組件中使用佔位標籤\n\n直接暫停結構體組件是不可能的。然而，您可以使用函數元件作為[高階元件](../advanced-topics/struct-components/hoc)來實現基於佔位標籤的資料取得。\n\nYew 倉庫中的[佔位標籤範例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)示範如何使用這個元件。\n\n## 相關範例\n\n- [佔位標籤](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: '建立一個範例應用'\n---\n\n當您的環境準備好後，您可以選擇使用一個包含基本 Yew 應用所需樣板的起始模板，或手動設定一個小項目。\n\n## 使用模板快速起步\n\n請依照 [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) 的安裝說明安裝工具，然後執行下列指令：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手動設定應用\n\n### 建立項目\n\n首先，請建立一個新的 cargo 專案。\n\n```bash\ncargo new yew-app\n```\n\n開啟新建立的目錄。\n\n```bash\ncd yew-app\n```\n\n### 運行一個 hello world 範例\n\n為了驗證 Rust 環境是否設定正確，使用 `cargo run` 執行初始專案。您應該會看到一個 \"Hello World!\" 訊息。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### 將項目設定為 Yew web 應用\n\n為了將這個簡單的命令列應用程式轉換為一個基本的 Yew web 應用程序，需要進行一些更改。\n\n#### 更新 Cargo.toml\n\n將 `yew` 加入到依賴清單中。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n# 開發版本的 Yew\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在建立一個應用程序，你只需要 `csr` 特性。它將啟用 `Renderer` 和所有與客戶端渲染相關的程式碼。\n\n如果你正在製作一個函式庫，請不要啟用此特性，因為它會將客戶端渲染邏輯拉入伺服器端渲染包中。\n\n如果你需要 Renderer 進行測試或範例，你應該在 `dev-dependencies` 中啟用它。\n\n:::\n\n#### 更新 main.rs\n\n我們需要產生一個模板，設定一個名為 `App` 的根元件，該元件渲染一個按鈕，當點擊時更新其值。用以下程式碼取代 `src/main.rs` 的內容。\n\n:::note\n`main` 函數中的 `yew::Renderer::<App>::new().render()` 呼叫啟動您的應用程式並將其掛載到頁面的 `<body>` 標籤上。如果您想要使用任何動態屬性啟動您的應用程序，您可以使用 `yew::Renderer::<App>::with_props(..).render()`。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### 建立 index.html\n\n最後，在應用程式的根目錄中新增一個 `index.html` 檔案。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## 查看您的 Web 應用\n\n運行以下命令在本地建置和提供應用程式。\n\n```bash\ntrunk serve\n```\n\n:::info\n新增選項 '--open' 來開啟您的預設瀏覽器 `trunk serve --open`。\n:::\n\nTrunk 將在您修改任何原始程式碼檔案時即時重新建立您的應用程式。\n預設情況下，伺服器將在位址 '127.0.0.1' 的連接埠 '8080' 上監聽 => [http://localhost:8080](http://127.0.0.1:8080)。\n若要變更這部分配置，請建立以下檔案並根據需要進行編輯：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 區域網路上的監聽位址\naddress = \"127.0.0.1\"\n# 廣域網路上的監聽位址\n# address = \"0.0.0.0\"\n# 監聽的端口\nport = 8000\n```\n\n## 恭喜\n\n現在您已經成功設定了您的 Yew 開發環境，並建立了您的第一個 Web 應用程式。\n\n嘗試這個應用程序，並查看[範例](./examples.mdx)以進一步學習。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/getting-started/editor-setup.mdx",
    "content": "---\ntitle: '設定編輯器'\ndescription: '設定您的程式碼編輯器'\n---\n\n:::important 改進文檔\n有在使用不同的編輯器？如有推薦，請隨意新增您選擇的編輯器的說明。\n:::\n\n## 為建立元件新增模板\n\n### JetBrains IDEs\n\n1. 從導覽列依序點擊 File | Settings | Editor | Live Templates.\n2. 選擇 Rust 並點選 + 圖示新增新的 Live Template。\n3. 根據需要給它一個的名稱和描述。\n4. 將以下程式碼片段貼到範本文字部分。\n5. 在右下角更改適用性，選擇 Rust > Item > Module\n\n對於函數式元件，使用以下模板。\n\n- (可選) 點選編輯變量，並給 `tag` 一個合理的預設值，例如 \"div\"，用雙引號。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n對於結構體組件，可以使用以下更複雜的模板。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. 從導覽列依序點選 File > Preferences > User Snippets.\n2. 選擇 Rust 作為設定語言。\n3. 在 JSON 檔案中加入以下程式碼片段：\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## 支援 `html!` 宏\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 擴展\n\n> 這是一個**正在進行中**的，**由社區維護**的項目！ [請查看詳細信息，並將相關的 bug 報告/問題/疑問直接發送到擴展的存儲庫](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 擴充 [可在 VSC Marketplace 上找到](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)，提供語法高亮、重新命名、懸停等功能。\n\nEmmet 支援應該可以直接使用，如果不能，請回退到編輯 `settings.json` 檔案：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> 下面的配置適用於[LazyVim](https://www.lazyvim.org) 配置和lazy.vim 插件，請在`lua/plugins/nvim-lspconfig.lua` 中建立一個檔案（或更新您的` lspconfig`）：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/getting-started/examples.mdx",
    "content": "---\ntitle: '範例'\n---\n\nYew 倉庫包含許多[範例]（維護狀態各異）。\n我們建議瀏覽它們以了解如何使用框架的不同功能。\n我們也歡迎拉取請求和問題，以便在它們不可避免地被忽略並需要一些幫助 ♥️ 時使用。\n\n有關更多詳細信息，包括示例列表，請參閱[README]。\n\n:::note\n大多數範例都有一個可以在 https://examples.yew.rs/< example_name > 找到的線上部署。\n在各自的子資料夾中的 README 頁面上點擊它們的徽章以導航到線上演示。\n:::\n\n[範例清單]: https://github.com/yewstack/yew/tree/master/examples\n[範例文件 README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/getting-started/introduction.mdx",
    "content": "---\ntitle: '開始使用'\n---\n\n你需要一些工具來編譯、建置、打包和調試你的 Yew 應用程式。在最開始，我們建議使用 [Trunk](https://trunkrs.dev/)。 Trunk 是用於 Rust 的 WASM Web 應用程式打包工具。\n\n## 安裝 Rust\n\n要安裝 Rust，請按照[官方說明](https://www.rust-lang.org/tools/install)。\n\n:::important\nYew 支援的最低 Rust 版本（MSRV）是 `1.84.0`。舊版將無法編譯。您可以使用 `rustup show`（在「active toolchain」下）或 `rustc --version` 檢查您的工具鏈版本。若要更新您的工具鏈，請執行 `rustup update`。\n:::\n\n## 安裝 WebAssembly 目標\n\nRust 可以為不同的「目標」（例如不同的處理器）編譯原始碼。用於基於瀏覽器的 WebAssembly 的編譯目標稱為 `wasm32-unknown-unknown`。以下命令將向您的開發環境新增 WebAssembly 目標。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## 安裝 Trunk\n\nTrunk 是建議的管理部署和包裝的工具，並在整個文件和範例中使用。\n\n```shell\n# 需要注意的是，這可能需要一段時間來安裝，因為它會從頭開始編譯所有內容\n# Trunk 也為許多主要的套件管理器提供了預先建置的二進位文件\n# 有關更多詳細信息，請參見 https://trunkrs.dev/#install\ncargo install --locked trunk\n```\n\n### 其他選項\n\n除了 Trunk 之外，還有其他選項可用於打包 Yew 應用程式。您可能想嘗試以下選項之一：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (仍在早期開發階段)\n\n## 下一步\n\n設定好開發環境後，現在可以繼續閱讀文件。如果您喜歡透過動手實作來學習，我們建議您查看我們的[教學](../tutorial)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: '從 0.22.0 遷移到 0.23.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` 不再在恆等分發時重新渲染\n\n`use_reducer` 現在在 reducer 返回相同的 `Rc` 時（透過指標相等性判斷）會跳過重新渲染。之前，每次分發都會觸發重新渲染。\n\n如果你的 reducer 有一個返回 `self` 不變的程式碼路徑，並且你依賴它來觸發重新渲染，請用 `use_force_update` 替代：\n\n<Tabs>\n  <TabItem value=\"before\" label=\"之前\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // 在 0.23 中這不再觸發重新渲染！\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"重新整理\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"之後\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"重新整理\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: '從 0.4.0 遷移到 0.5.0'\n---\n\n沒有破壞性變更。在 `Cargo.toml` 中將 yew-agent 更新到 0.5.0。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: '從 0.19.0 遷移到 0.20.0'\n---\n\n沒有破壞性變更。在 `Cargo.toml` 中將 yew-router 更新到 0.20.0。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\n一個關於如何最好地將CSS 支援整合到Yew 中的討論可以在這裡找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n這裡包含了很多關於如何最好地將 CSS 支援整合到 Yew 中的討論。\n\n目前，我們採用的方法是鼓勵開發者在採用最受歡迎的系統之前建立許多系統。\n\n社區目前正在開發幾個項目，以便為項目添加樣式。以下是其中的一些：\n\n#### 元件庫\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - 沒有任何 JavaScript 依賴的 Yew 樣式框架。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design 元件。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS 元件。\n- [Yewtify](https://github.com/yewstack/yewtify) – 在 Yew 中實作 Vuetify 框架所提供的功能。\n\n#### 樣式解決方案\n\n- [stylist](https://github.com/futursolo/stylist-rs) - 用於 WebAssembly 應用程式的 CSS-in-Rust 樣式解決方案。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind 實用類別。\n\n:::important 改進文檔\n如果您正在開發一個為 Yew 添加樣式的項目，請提交一個 PR 將自己添加到這個列表中！\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/more/debugging.mdx",
    "content": "---\ntitle: '調試'\n---\n\n## 意外終止 (Panics)\n\nYew 會自動在瀏覽器控制台中輸出意外終止日誌。\n\n## 控制台日誌\n\n在 JavaScript 中，`console.log()` 用於輸出到瀏覽器控制台。以下是一些 Yew 的選項。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate 與 [`log`](https://crates.io/crates/log) crate 集成，以將日誌等級、來源行和檔案名稱傳送到瀏覽器控制台。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\n這個 crate 是 Gloo 的一部分，提供了對瀏覽器 API 的 Rust 包裝。 `log!` 巨集可以直接接受 `JsValue`，比 `wasm_logger` 更容易使用。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` 可以與 [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) 一起使用，將訊息輸出到瀏覽器控制台。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## 偵錯元件生命週期\n\n[`tracing`](https://crates.io/crates/tracing) 可用於收集與組件生命週期相關的事件資訊。 `tracing` 還附帶一個 `log` 支援的特性標誌，可以與 `wasm-logger` 很好地整合。\n\n[編譯時過濾器](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) 可以用於調整詳細程度或停用日誌記錄，這應該會導致更小的Wasm 檔案。\n\n## 來源映射 (Source Maps)\n\n有一些支援 [來源映射](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf)。但是，需要一些配置。\n\n## 過去的文章\n\n以下是一些關於 Rust 中 WebAssembly 偵錯狀態的過去文章。它們可能是有趣的閱讀。\n\n\\[Dec 2019\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 這些工作還有很多要做。例如，在工具方面，Emscripten（Binaryen）和 wasm-pack（wasm-bindgen）尚未支援在它們執行的轉換上更新 DWARF 資訊。\n\n\\[2020\\] [Rust Wasm 偵錯指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸的是，WebAssembly 的調試能力仍然不成熟。在大多數Unix 系統上，[DWARF](http://dwarfstd.org/) 用於編碼調試器需要提供運行中程序的源級檢查的信息，就連在Windows 上有一種編碼類似信息的替代格式。但目前，WebAssembly 並沒有對應的格式。\n\n\\[2019\\] [Rust Wasm 路線圖](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 偵錯很棘手，因為很多情況不在這個工作小組的掌控之中，而是取決於 WebAssembly 標準化機構和實現瀏覽器開發者工具的人。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/more/deployment.mdx",
    "content": "---\ntitle: '部署'\ndescription: '部署 Yew 應用程式'\n---\n\n當您準備將 Yew 應用程式部署到伺服器時，您有多種部署方案可以選擇。\n\n`trunk build --release` 會以發布模式建立您的應用程式。設定您的HTTP 伺服器，以便在存取您的網站時提供`index.html`，並且對於靜態路徑（例如`index_<hash>.js` 和`index_bg_<hash>.wasm`）的請求，應該從trunk產生的dist 目錄中提供相應的內容。\n\n:::important 有關 `trunk serve --release`\n不要在生產環境中使用 `trunk serve --release` 來提供您的應用程式。\n它只應該用於在開發過程中測試發布版本建置。\n:::\n\n## 伺服器配置\n\n### 將 `index.html` 當作回退提供\n\n如果應用程式使用了 [Yew 路由](concepts/router.mdx)，您必須設定伺服器在請求不存在的檔案時傳回 `index.html`。\n\n具有 Yew 路由的應用程式被建構為 [單頁應用程式 (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA)。當使用者從正在執行的用戶端導覽到 URL 時，路由器會解釋 URL 並路由到該頁面。\n\n但是在刷新頁面或在網址列中輸入 URL 時，這些操作都是由瀏覽器本身處理的，而不是由正在執行的應用程式處理。瀏覽器直接向伺服器請求該 URL，繞過了路由器。錯誤配置的伺服器會回傳 404 - 未找到 狀態。\n\n透過返回 `index.html`，應用程式會像通常一樣加載，就好像請求是 `/`，直到路由器注意到路由是 `/show/42` 並顯示相應的內容。\n\n### 為 Web Assembly 資源配置正確的 MIME 類型。\n\nWASM 檔案必須使用 `application/wasm` MIME 類型設定 [Content-Type 頭](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。\n\n大多數伺服器和託管服務預設已經這樣做。如果您的伺服器沒有這樣做，請查閱其文件。在大多數 Web 瀏覽器中，錯誤的 MIME 類型會導致類似以下的錯誤：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 為相對路徑構建\n\n預設情況下，trunk 會假定您的網站在 `/` 處提供，並相應地建立網站。可以透過在 `index.html` 檔案中加入 `<base data-trunk-public-url />` 來覆寫此行為。 Trunk 會重寫此標籤以包含傳遞給 `--public-url` 的值。 Yew 路由會自動偵測 `<base />` 的存在並適當處理。\n\n## 使用環境變數自訂行為\n\n通常使用環境變數來自訂建構環境。由於應用程式在瀏覽器中運行，我們無法在運行時讀取環境變數。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) 巨集可以在編譯時取得環境變數的值。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/more/roadmap.mdx",
    "content": "---\ntitle: '路線圖'\ndescription: 'Yew 框架的計劃功能路線圖'\n---\n\n## 優先權\n\n框架即將推出的功能和重點的優先順序由社群決定。\n在 2020 年春季，我們發送了一份開發者調查，以收集關於專案方向的回饋。\n您可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到調查摘要。\n\n:::note\n所有主要倡議的狀態都可以在 Yew Github [專案看板](https://github.com/yewstack/yew/projects) 上跟踪\n:::\n\n## 重點\n\n1. 最受歡迎的功能\n2. 生產就緒\n3. 文件\n4. 痛點\n\n### 最受歡迎的功能\n\n1. [函數組件](https://github.com/yewstack/yew/projects/3)\n2. [元件庫](https://github.com/yewstack/yew/projects/4)\n3. 更好的狀態管理\n4. [伺服器端渲染](https://github.com/yewstack/yew/projects/5)\n\n### 生產就緒所需的問題\n\n- 提高 Yew 測試覆蓋率\n- 減少二進位檔案大小\n- [效能基準測試](https://github.com/yewstack/yew/issues/5)\n\n### 文件\n\n- 建立教程\n- 簡化項目設置\n\n### 痛點\n\n- [組件樣板](https://github.com/yewstack/yew/issues/830)\n- [代理](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/more/testing.mdx",
    "content": "---\ntitle: '測試應用'\ndescription: '測試你的應用程式'\n---\n\n:::info\n我們正在努力讓測試組件變得更容易，但目前仍在進行中。\n\n在 GitHub 倉庫中可以找到對 [淺渲染](https://github.com/yewstack/yew/issues/1413) 的支援。\n:::\n\n## 快照測試\n\nYew 提供了 `yew::tests::layout_tests` 模組來方便元件的快照測試。\n\n:::important 改進文檔\n我們需要幫助，以改進快照測試的文件。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM 工作小組維護了一個稱為 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) 的 crate，\n它允許你以類似於內建的 `#[test]` 過程巨集的方式在瀏覽器中執行測試。\n有關此模組的更多信息，請參閱 [Rust Wasm 工作組的文檔](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/tutorial/index.mdx",
    "content": "---\ntitle: '教學'\nslug: /tutorial\n---\n\n## 介紹\n\n在這個實作教程中，我們將學習如何使用 Yew 建立 Web 應用程式。\n**Yew** 是一個現代的 [Rust](https://www.rust-lang.org/) 框架，用於使用 [WebAssembly](https://webassembly.org/) 建立前端 Web 應用程式。\nYew 透過利用 Rust 強大的類型系統，鼓勵可重複使用、可維護和良好結構化的架構。\n一個龐大的社群所創造的函式庫生態系統，稱為Rust 中的[crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)，為常用模式（如狀態管理）提供了元件。\nRust 的套件管理器 [Cargo](https://doc.rust-lang.org/cargo/) 允許我們利用 [crates.io](https://crates.io) 上提供的大量 crate，例如 Yew。\n\n### 我們將要建構的內容\n\nRustconf 是 Rust 社群每年舉辦的星際派對。\nRustconf 2020 有大量的演講，提供了大量的資訊。\n在這個實作教程中，我們將建立一個 Web 應用程序，幫助其他 Rustaceans 了解這些演講並從一個頁面觀看它們。\n\n## 設定\n\n### 先決條件\n\n這個教程假設您已經熟悉 Rust。如果您是Rust 的新手，免費的[Rust 書](https://doc.rust-lang.org/book/ch00-00-introduction.html) 為初學者提供了一個很好的起點，並且即使對於有經驗的Rust 開發人員來說，它仍然是一個很好的資源。\n\n確保安裝了最新版本的 Rust，方法是執行 `rustup update` 或[安裝 Rust](https://www.rust-lang.org/tools/install)。\n\n安裝 Rust 後，您可以使用 Cargo 執行以下命令安裝 `trunk`：\n\n```bash\ncargo install trunk\n```\n\n我們還需要新增 WASM 建置目標，執行以下命令：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### 設定項目\n\n首先，建立一個新的 cargo 專案：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\n為了驗證 Rust 環境是否設定正確，使用 cargo 建置工具執行初始專案。\n在關於建置過程的輸出之後，您應該會看到預期的 \"Hello, world!\" 訊息。\n\n```bash\ncargo run\n```\n\n## 我們的第一個靜態頁面\n\n為了將這個簡單的命令列應用程式轉換為一個基本的 Yew web 應用程序，需要進行一些更改。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { git = \"https://github.com/yewstack/yew/\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在建立一個應用程序，你只需要 `csr` 特性。它將啟用 `Renderer` 和所有與客戶端渲染相關的程式碼。\n\n如果你正在製作一個函式庫，請不要啟用此特性，因為它會將客戶端渲染邏輯拉入伺服器端渲染包中。\n\n如果你需要 Renderer 進行測試或範例，你應該在 `dev-dependencies` 中啟用它。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n現在，讓我們在專案的根目錄中建立一個 `index.html`。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 啟動開發伺服器\n\n運行以下命令建置並在本地提供應用程式。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n刪除選項 '--open' 以在執行 `trunk serve` 後不開啟預設瀏覽器。\n:::\n\nTrunk 將在您修改任何原始程式碼檔案時即時重新建立您的應用程式。\n預設情況下，伺服器將在位址 '127.0.0.1' 的連接埠 '8080' 上監聽 => [http://localhost:8080](http://127.0.0.1:8080)。\n若要變更這部分配置，請建立以下檔案並根據需要進行編輯：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 區域網路上的監聽位址\naddress = \"127.0.0.1\"\n# 廣域網路上的監聽位址\n# address = \"0.0.0.0\"\n# 監聽的端口\nport = 8000\n```\n\n如果您有興趣，您可以執行 `trunk help` 和 `trunk help <subcommand>` 以獲取更多關於正在進行的流程的詳細資訊。\n\n### 恭喜\n\n您現在已經成功設定了 Yew 開發環境，並建立了您的第一個 Yew Web 應用程式。\n\n## 建立 HTML\n\nYew 利用了 Rust 的過程宏，並為我們提供了一種類似於 JSX（JavaScript 的擴展，可讓您在 JavaScript 中編寫類似 HTML 的程式碼）的語法來建立標記。\n\n### 轉換為經典 HTML\n\n由於我們已經對我們的網站長什麼樣子有了一個很好的想法，我們可以簡單地將我們的草稿轉換為與 `html!` 相容的表示。如果您習慣於編寫簡單的 HTML，那麼您在 `html!` 中編寫標記時應該沒有問題。要注意的是，這個巨集與 HTML 有一些不同之處：\n\n1. 表達式必須用大括號（`{ }`）括起來\n2. 只能有一個根節點。如果您想要在不將它們包裝在容器中的情況下擁有多個元素，可以使用空標籤/片段（`<> ... </>`）\n3. 元素必須正確關閉。\n\n我們想要建立一個佈局，原始 HTML 如下：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\n現在，讓我們將這個 HTML 轉換為 `html!`。將下列程式碼片段輸入（或複製/貼上）到 `app` 函數的主體中，以便函數傳回 `html!` 的值\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\n刷新瀏覽器頁面，您應該看到以下輸出：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### 在標記中使用 Rust 語言結構\n\n在 Rust 中編寫標記的一個很大的優勢是，我們在標記中獲得了 Rust 的所有優點。\n現在，我們不再在 HTML 中硬編碼影片列表，而是將它們定義為 `Vec` 的 `Video` 結構體。\n我們建立一個簡單的 `struct`（在 `main.rs` 或我們選擇的任何檔案中）來保存我們的資料。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n接下來，我們將在 `app` 函數中建立這個結構體的實例，並使用它們來取代硬編碼的資料：\n\n```rust\nuse website_test::tutorial::Video; // 換成你自己的路徑\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\n為了顯示它們，我們需要將 `Vec` 轉換為 `Html`。我們可以透過建立一個迭代器，將其映射到 `html!` 並將其收集為 `Html` 來實現：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\n在清單項目上使用鍵有助於 Yew 追蹤清單中哪些項目發生了變化，從而實現更快的重新渲染。 [始終建議在清單中使用鍵](/concepts/html/lists.mdx#keyed-lists)。\n:::\n\n最後，我們需要用從資料建立的 `Html` 取代硬編碼的影片清單：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## 元件\n\n組件是 Yew 應用程式的構建塊。透過組合組件（可以由其他組件組成），我們建立我們的應用程式。透過為可重複使用性建立元件並保持它們的通用性，我們將能夠在應用程式的多個部分中使用它們，而無需重複程式碼或邏輯。\n\n到目前為止我們一直在使用的 `app` 函數是一個元件，稱為 `App`。它是一個「函數式元件」。\n\n1. 結構體組件\n2. 函數式組件\n\n在本教程中，我們將使用函數式元件。\n\n現在，讓我們將 `App` 元件拆分為更小的元件。我們首先將影片清單提取到自己的組件中。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n注意我們的 `VideosList` 函數元件的參數。函數元件只接受一個參數，該參數定義了它的 \"props\"（\"properties\" 的縮寫）。 Props 用於從父元件傳遞資料到子元件。在這種情況下，`VideosListProps` 是一個定義 props 的結構體。\n\n:::important\n用於 props 的結構體必須透過派生實作 `Properties`。\n:::\n\n為了讓上面的程式碼編譯通過，我們需要修改 `Video` 結構體如下：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n現在，我們可以更新我們的 `App` 元件以使用 `VideosList` 元件。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n透過查看瀏覽器窗口，我們可以驗證清單是否按預期呈現。我們已經將清單的渲染邏輯移動到了它的元件中。這縮短了 `App` 元件的原始程式碼，使我們更容易閱讀和理解。\n\n### 使應用程式可以交互\n\n這裡的最終目標是顯示所選影片。為了做到這一點，`VideosList` 元件需要在選擇影片時「通知」其父元件，這是透過 `Callback` 完成的。這個概念稱為「傳遞處理程序」。我們修改其 props 以接受一個 `on_click` 回呼：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n然後我們修改 `VideosList` 元件以將所選影片傳遞給回呼。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n接下來，我們需要修改 `VideosList` 的使用以傳遞該回呼。但在這樣做之前，我們應該建立一個新的元件 `VideoDetails`，當點擊影片時才會顯示。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n現在，修改 `App` 元件以在選擇影片時顯示 `VideoDetails` 元件。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n現在不用擔心 `use_state`，我們稍後會回到這個問題。注意我們用 `{ for details }` 提取列表資料的技巧。\n`Option<_>` 實作了`Iterator`，所以我們可以使用特殊的`{ for ... }` 語法來逐個顯示`Iterator` 返回的唯一元素，而這[由`html!` 巨集支援](concepts/html/lists)。\n\n### 處理狀態\n\n還記得之前使用的 `use_state` 嗎？那是一個特殊的函數，稱為 \"hook\"。 Hooks 用於 \"hook\" 到函數元件的生命週期中並執行操作。您可以在[這裡](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)了解更多關於這個 hook 和其他 hook 的資訊。\n\n:::note\n結構體組件的行為不同。請查看[文件](advanced-topics/struct-components/introduction.mdx)以了解有關這些的資訊。\n:::\n\n## 取得資料（使用外部 REST API）\n\n在真實的應用程式中，資料通常來自 API 而不是硬編碼。讓我們從外部來源取得我們的影片清單。為此，我們需要添加以下 crate：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  用於進行 fetch 調用。\n- [`serde`](https://serde.rs) 及其衍生特性\n  用於反序列化 JSON 回應\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  用於將 Rust 的 Future 作為 Promise 執行\n\n讓我們更新 `Cargo.toml` 檔案中的依賴項：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n在選擇依賴項時，請確保它們與 `wasm32` 相容！否則，您將無法運行您的應用程式。\n:::\n\n更新 `Video` 結構體以衍生 `Deserialize` 特性：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n最後一步，我們需要更新我們的 `App` 元件，以便進行 fetch 請求，而不是使用硬編碼的數據\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\n我們在這裡使用 `unwrap`，因為這是一個演示應用程式。在真實的應用程式中，您可能希望有[適當的錯誤處理](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)。\n:::\n\n現在，查看瀏覽器，看看一切是否按預期工作……如果不是因為 CORS 的話。為了解決這個問題，我們需要一個代理伺服器。幸運的是 trunk 提供了這個功能。\n\n更新這些行：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n現在，使用以下命令重新運行伺服器：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\n刷新網頁，一切都應該按預期工作。\n\n## 總結\n\n恭喜！您已經建立了一個從外部 API 取得資料並顯示影片清單的 Web 應用程式。\n\n## 接下來\n\n這個應用程式離完美或有用還有很長的路要走。完成本教學後，您可以將其作為探索更高級主題的起點。\n\n### 樣式\n\n我們的應用程式看起來非常醜陋。沒有 CSS 或任何樣式。不幸的是，Yew 沒有提供內建的樣式組件。請查看 [Trunk 的 assets](https://trunkrs.dev/assets/)，以了解如何新增樣式表。\n\n### 更多依賴函式庫\n\n我們的應用程式只使用了很少的外部依賴。有很多 crate 可以使用。請查看[外部程式庫](/community/external-libs)以取得更多詳細資訊。\n\n### 了解更多關於 Yew\n\n閱讀我們的[官方文件](../getting-started/introduction.mdx)。它更詳細地解釋了許多概念。要了解有關 Yew API 的更多信息，請查看我們的[API 文件](https://docs.rs/yew)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/current.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"從零開始\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"核心觀念\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Function Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"進階主題\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"進階主題\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"更多\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Intro With Basic Web Technologies\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew mostly operates on the idea of keeping everything that a reusable piece of UI may need, in one place - rust files. But also seeks to stay close to the original look of the technology. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/advanced-topics/how-it-works.mdx",
    "content": "---\ndescription: 關於框架的底層細節\n---\n\n# 內部底層的 library\n\n元件生命周期的狀態機與 vdom diff 演算法\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/advanced-topics/optimizations.mdx",
    "content": "---\ndescription: 加速你的專案\n---\n\n# 優化與最佳實例\n\n## neq_assign\n\n當元件從父元件接收到屬性時， `change` 的方法就會被呼叫。除了讓你更新元件的狀態，也讓你回傳，決定元件是否要在屬性改變時，重新渲染自己的布林值 `ShouldRender` 。\n\n重新渲染是很浪費效能的，儘可能避免這麼做。一般來說，只有在屬性真的改變時，才重新渲染。下面的程式碼是體現這個原則的例子，當屬性改變時，才回傳 `true`：\n\n```rust\nuse yew::ShouldRender;\n\n#[derive(PartialEq)]\nstruct ExampleProps;\n\nstruct Example {\n    props: ExampleProps,\n};\n\nimpl Example {\n    fn change(&mut self, props: ExampleProps) -> ShouldRender {\n        if self.props != props {\n            self.props = props;\n            true\n        } else {\n            false\n        }\n    }\n}\n```\n\n但我們可以走的更遠！這六行的模板，使用一個 trait 和一個 實作了 `PartialEq` 的 blanket implementation ，可以被縮短至一行。請參考[這裡](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html)， `yewtil` 的 crate 裡的 `NeqAssign` trait。\n\n## RC\n\n為了避免重新渲染時，複製大量的資料來建立屬性，我們可以使用智慧指針來讓程式只複製指針。如果你使用 `Rc<_>` 來封裝你的屬性，而不是未封裝的值，你可以使用 `Rc::make_mut`，去複製與存取你想要改變的資料的可變參考，這做到了延遲複製，直到你需要更動子元件的資料。透過避免複製直到有值改變，子元件可以在 `Component::change` 拒絕與他狀態中的屬性相同值的屬性，而且這樣不會有任何效能成本。另外，這個方式，資料必須在與子元件比較與被拒絕之前，被複製進父元件的屬性中。\n\n這個優化最那些無法 `Copy` 的資料型別最有用。如果你可以輕易複製你的資料，那把資料放進智慧指針裡面似乎就沒有這麼值得。對於那些包含很多像是 `Vec` 、 `HashMap` 與 `String` 的結構，這個優化對他們會更值得。\n\n如果子元件幾乎不會更新值，那這個優化效果會很好，甚至如果父元件也很少更新，那效果會更好。上面的情況，使在純元件中使用 `Rc<_>s` 是一個封裝屬性值很好的選擇。\n\n## View 方法\n\n出於程式碼的可讀性，通常會寫方法包裝複雜的 `html!`，這樣你可以避免巢狀的 HTML 造成過多的向右縮排。\n\n## 純元件/函數式元件\n\n純元件 是一種不會改變自己狀態的元件，他們只單純顯示內容或是向普通可變的元件傳送訊息。他們和 view 方法不同的地方在於們可以在 `html!` 巨集中使用，語法會像（`<SomePureComponent />`），而不是表達式語法（`{some_view_function()}`），而且根據他們的實作方式，他們可以被 memoized，這樣可以套用前面所述的 `neq_assign` 的邏輯避免重新渲染。\n\nYew 本身不支援純元件或是函數式元件，但是你可以透過 external crates 使用。\n\n函數式元件還不存在，但是理論上純元件可以透過巨集與宣告方法產生。\n\n## Keyed DOM nodes when they arrive\n\n## 使用 Cargo Workspaces 加速編譯\n\nYew 最大的缺點就是花太多時間在編譯上了。編譯時間似乎和 `html!` 巨集中的程式碼質量相同。 對於小專案來說，這應該不是什麼大問題，但是對於有很多頁面的大型網頁應用程式來說，就必須要將程式碼封裝成很多 crates 以減少編譯所花的時間。\n\n你應該將路由與頁面區塊封裝成一個 main crate，然後將共用的程式碼與元件封裝成另一個 crate，將每個頁面會用到的不同的元件，各自封裝到不同的 crate 中，或是只產生 `Html` 的大方法中。最好的狀況，你只需要重新編譯你 main crate 與修改的頁面的 crate 的程式碼；而最壞的情況，你編輯了共用的 crate，你就必須重新編譯所有依賴這個共用 crate 的程式碼。\n\n如果你的 main crate 太過龐大，或是你希望快速迭代深層巢狀的頁面（一個頁面渲染另一個頁面的頂層），你可以使用範例的 crate ，在一個簡單的主頁面上編輯你未完成的元件。\n\n## 編譯大小的優化 <a id=\"build-size-optimization\"></a>\n\n- 優化 Rust 的程式碼\n- `cargo.toml` （定義釋出的設定檔）\n- 使用 `wasm-opt` 優化 wasm 程式碼\n\n更多關於程式碼大小的資訊，請參考： [rustwasm book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n\n### Cargo.toml <a id=\"cargo-toml\"></a>\n\n你可以設定你的發行版本更小的檔案大小，透過設定 `Cargo.toml` 的 `[profile.release]` 。\n\n[Rust profiles documentation](https://doc.rust-lang.org/cargo/reference/profiles.html)\n\n```rust\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### wasm-opt <a id=\"wasm-opt\"></a>\n\n更多優化 `wasm` 程式碼大小的方法。\n\nwasm-opt 資訊： [binaryen project](https://github.com/WebAssembly/binaryen)\n\nRust Wasm 中有一個關於減少 Wasm 二進位檔大小的章節：[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用`wasm-pack` 預設在發行版本編譯時優化 `wasm` 程式碼\n- 直接在 wasm 檔案上使用 `wasm-opt` 。\n\n```rust\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 編譯 yew/examples/ 中 最小的例子 <a id=\"build-size-of-minimal-example-in-yew-examples\"></a>\n\n注意： `wasm-pack` 包含對 Rust 與 wasm 程式碼的優化。而`wasm-bindgen` 只是一個單純的例子，沒有對 `Rust` 做任何優化。\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-binggen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99KB  |\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ndescription: ComponentLink 與 Callbacks.\n---\n\n# Callbacks\n\n元件的「link」是一個讓元件註冊 callbacks 並自我更新的機制。\n\n## ComponentLink API\n\n### callback\n\n註冊一個 callback 後，當這個 callback 被執行時，會發送一個訊息給元件的更新機制。在生命周期的勾子下，他會呼叫 `send_self` 並將被閉包回傳的訊息帶給他。\n\n提供一個 `Fn(IN) -> Vec<COMP::Message>` 並回傳一個 `Callback<IN>` 。\n\n### send_message\n\n當現在的迴圈結束後，向元件發送訊息，並且開啟另一個迴圈。\n\n### send_message_batch\n\n註冊一個 callback，當這個 callback 被執行時，這個 callback 會一次送很多訊息。如果有任何一個訊息導致元件被重新渲染，元件會在所有批次送來的訊息都被處理完後，再重新渲染。\n\n提供一個 `Fn(IN) -> COMP::Message` 並回傳一個 `Callback<IN>` 。\n\n## Callbacks\n\n_（他可能需要一個獨立的短頁來介紹）_\n\nCallbacks 被用來當作 services 、 agents 與父元件跟 Yew 溝通的方式。他們只是一個被 `Rc` 包裹著的 `Fn`，好讓他們可以被複製。\n\n他們有一個 `emit` 方法，這個方法拿他們的 `<IN>` 型別當作參數，並且轉換他作為目的地所期望的訊息。如果一個從父元件來的 callback 被提供作為子元件的屬性，子元件可以在他的 update 生命周期中，呼叫 callback 中的 emit 以傳遞訊息回給父元件。 在 `html!` 巨集中的閉包與方法如果被當作屬性傳遞，會被自動轉為 Callbacks。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ndescription: 元件，以及生命周期鉤子\n---\n\n# 元件\n\n## 什麼是元件？\n\n元件是 Yew 的基石。他們管理自己的狀態，可以渲染自己成為 DOM。元件可以透過實作，描述元件生命周期的 `Component` trait 來建立。\n\n## 生命周期\n\n:::note\n`歡迎來貢獻我們的文件：` [Add a diagram of the component lifecycle](https://github.com/yewstack/docs/issues/22)\n:::\n\n## 生命周期的方法\n\n### Create\n\n當一個元件被建立，他會接收從父元件，也就是 `ComponentLink` ，傳下來的屬性。 這些屬性用來初始化元件的狀態，此外，「link」可以用來註冊回調函式或傳訊息給元件。\n\n通常，你的元件 struct 會儲存 props 與 link，就像下面的例子：\n\n```rust\npub struct MyComponent {\n    props: Props,\n    link: ComponentLink<Self>,\n}\n\nimpl Component for MyComponent {\n    type Properties = Props;\n    // ...\n\n    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { props, link }\n    }\n\n    // ...\n}\n```\n\n### View\n\n元件會在 `view()` 方法中宣告佈局。Yew 提供 `html!` 巨集來宣告 HTML 合 SVG 的結點，包含他們的監聽事件與子結點。這個巨集扮演像是 React 的 JSX 的角色，但是是使用 Rust 的表達式，而不是 JavaScript 的。\n\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        let onclick = self.link.callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ self.props.button_text }</button>\n        }\n    }\n}\n```\n\n更多使用細節，請參考 [`html!` 教學](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered()` 生命周期的方法會，在 `view()` 處理完並且 Yew 渲染完你的元件之後，與瀏覽器刷新頁面之前，被呼叫。一個元件可能希望實作這個方法，去執行只能在元件被渲染完元素才能做的事情。 你可以透過 `first_render` 變數來確認這個元件是不是第一次被渲染。\n\n```rust\nuse stdweb::web::html_element::InputElement;\nuse stdweb::web::IHtmlElement;\nuse yew::prelude::*;\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    // ...\n\n    fn view(&self) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    fn rendered(&mut self, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<InputElement>() {\n                input.focus();\n            }\n        }\n    }\n}\n```\n\n:::note\n注意，這個生命周期方法，不是一定要被實作，預設的行為是不做任何事情。\n:::\n\n### Update\n\n元件是可動態更新且可以註冊接收非同步的訊息。 `update()` 生命周期方法會被每個訊息呼叫。他基於訊息是什麼，來允許元件更新自己，且會決定是否需要重新渲染。 訊息可以被 HTML 元素的監聽器觸發，或被子元件、Agents、Services 或 Futures 傳送。\n\n`update()` 應用範例：\n\n```rust\npub enum Msg {\n    SetInputEnabled(bool)\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n\n    // ...\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n       match msg {\n           Msg::SetInputEnabled(enabled) => {\n               if self.input_enabled != enabled {\n                   self.input_enabled = enabled;\n                   true // 重新渲染\n               } else {\n                   false\n               }\n           }\n       }\n    }\n}\n```\n\n### Change\n\n元件可能會被他的父元件重新渲染。當他被父元件重新渲染時，他會收到新的屬性，然後決定要不要再渲染一次。 這設計是讓父元件透過便於跟子元件溝通。\n\n一個簡單的實作方式像：\n\n```rust\nimpl Component for MyComponent {\n    // ...\n\n    fn change(&mut self, props: Self::Properties) -> ShouldRender {\n        if self.props != props {\n            self.props = props;\n            true\n        } else {\n            false\n        }\n    }\n}\n```\n\n### Destroy\n\n當元件從 DOM 上被解除掛載，Yew 會呼叫 `destroy()` 生命周期方法以提供任何需要清理的操作。這個方法是不一定要被實作的，預設不會做設任何事。\n\n## 相關的型別\n\n`Component` trait 有兩個相關的型別：`Message` 與 `Properties`。\n\n```rust\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 負責各式各樣的訊息，他可能被元件處理去觸發各種影響。舉例來說，你可能有一個 `Click` 的訊息，他會觸發 API 請求，或是切換 UI 元件的樣貌。下面是一個常見的實作，在你的元件模組中，創建一個叫作 `Msg` 的 enum，然後把他當作元件裡的 Message 型別。通常 message 會縮寫成 msg。\n\n```rust\nenum Msg {\n    Click,\n}\n```\n\n`Properties` 代表要從父員件傳遞到子元件的資訊。這個型別必須實作 `Properties` trait （通常會 deriving 他）並且可以決定某個屬性是必要的屬性，或是可選的屬性。這個型別會在創建元件的時候，或是更新元件的時候被使用到。常見的實作會在你的元件模組中，建立一個叫作 `Props` 的 struct，然後把他當作元件的`Properties` 型別。通常 properties 或縮寫成 props。因為屬性是從父原件被傳下來的，所以應用程式中的根元件的 `Properties` 原則上都是 `()`。如果你希望你的根元件有特定的屬性，可以使用 `App::mount_with_props` 的方法。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/properties.mdx",
    "content": "---\ndescription: 父元件與子元件的溝通橋樑\n---\n\n# Properties\n\n屬性讓子元件與父元件可以互相溝通。\n\n## Derive macro\n\n不要嘗試自己實作 `Properties`，而是用`#[derive(Properties)]`derive 他。\n\n### 必填的欄位\n\n預設所有在 `Properties` struct 裡的欄位都是必填的。當必填的欄位沒有值，而元件在 `html!` 巨集中又被建立，編譯器就會報錯。如果希望欄位是可選的，可以使用 `#[prop_or_default]` 來讓該欄位有預設值。如果希望欄位預設特定值，可以使用 `#[prop_or_else(value)]` ，裡面的 value 就會是這個欄位的預設值。舉例來說，希望預設值是 `true`可以在欄位宣告上面這樣寫 `#[prop_or_else(true)]`. 通常可選的屬性，會用 `Option` ，且預設值為`None`。\n\n### PartialEq\n\n如果可以，最好在你的屬性上面 derive `PartialEq` 。他可以避免畫面多餘的渲染，更細節的內容請參考，**優化與最佳實例**的區塊。\n\n## 屬性的記憶體與速度的開銷\n\n在 `Component::view`,裡，你可以拿到元件狀態的參考，且用他來建立 `Html` 。但是屬性是有所有權的。這代表著為了建立屬性，並且將他們傳遞給子元件，我們必須取得被 `view` 方法拿走的所有權。 當將參考傳給元件時，可以透過隱式的複製來做到得到所有權。\n\n這意味著，每個元件，都有從父元件傳遞下來的獨有的狀態複本，且每當你重新渲染一次元件，被重新渲染的元件的所有的子元件的屬性就會被重新複製一次。\n\n代表如果你要在屬性中傳遞*大量*的資料（大於 10 KB 的字串之類的），你可能需要考慮將你的子元件變成一個回傳 `Html` 的方法，讓父元件呼叫，以避免資料被複製。\n\n如果你不需要改變傳下去的資料，你可以用 `Rc` 將資料包裝起來，這樣就會只複製參考的指針，而不是資料本身。\n\n## 範例\n\n```rust\nuse std::rc::Rc;\nuse yew::Properties;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nimpl Default for LinkColor {\n    fn default() -> Self {\n        // 除非有指定，否則預設是藍色\n        LinkColor::Blue\n    }\n}\n\n#[derive(Properties, Clone, PartialEq)]\npub struct LinkProps {\n    /// 連結必須要有一個目標\n    href: String,\n    /// 如果連結文字很大，複製字串的參考可以減少記憶體的開銷\n    /// 但除非效能已經成為嚴重的問題，否則通常不建議這麼做\n    text: Rc<String>,\n    /// 連結的顏色\n    #[prop_or_default]\n    color: LinkColor,\n    /// 如果為 None，那 view 方法將不會指定 size\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當沒有指定 active，預設為 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/advanced-topics/struct-components/refs.mdx",
    "content": "---\ndescription: 外帶 DOM 的存取\n---\n\n# Refs\n\n## Refs\n\n`ref` 關鍵字可以被使用在任何 HTML 的元素或是元件，用來得到那個物件附加的 DOM `Element`。這個可以在 view 生命周期方法之外，改變 DOM。\n\n對於要存取 canvas 元素，或滾動到頁面不同的區塊，很有幫助。\n\n語法可以這樣使用：\n\n```rust\n// 建立\nself.node_ref = NodeRef::default();\n\n// 在 view 裡\nhtml! {\n    <div ref={self.node_ref.clone()}></div>\n}\n\n// 更新\nlet has_attributes = self.node_ref.cast::<Element>().unwrap().has_attributes();\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/agents.mdx",
    "content": "---\ndescription: Yew 的 Actor 系統\n---\n\n# Agents\n\nAgents 類似於 Angular 的 [Services](https://angular.io/guide/architecture-services) （但沒有依賴注入）而且提供 Tew 一個 [Actor Model](https://en.wikipedia.org/wiki/Actor_model). Agents 可以用來作為兩個元件間的路由訊息，而且與他們在元件間的層級關係獨立出來，所以他也可以用來作為一個全域的狀態，甚至可以用來減輕用來渲染 UI 畫面的主執行緒的大量運算任務。 未來，我們還規劃要讓 agents 幫忙 Yew 專案可以跨頁籤溝通。\n\n為了讓 agents 可以並行， Yew 使用了 [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命周期\n\n![Agent 生命周期](https://user-images.githubusercontent.com/42674621/79125224-b6481d80-7d95-11ea-8e6a-ab9b52d1d8ac.png)\n\n## Agents 的型別\n\n#### 範圍\n\n- Job - 在 UI 執行緒上，為每一個 bridge，新增一個 agent。這對於將「共享但獨立的行為」移出元件很有用。（待驗證）當工作結束，agent 會消失。\n- Context - Bridges 會建立並連接上 UI 執行緒上的 agent。這可以用來協調元件與其他 agent 之間的狀態。當沒有任何 bridge 連接上這個 agent，這個 agnet 就會消失。\n- Private - 與 Job 相同，但是是在自己的 web worker 上執行的。\n- Public - 與 Context 相同，但是是在自己的 web worker 上執行的。\n- Global （編寫中）\n\n## 在 Agents 與元件之間溝通\n\n### Bridges\n\nbridge 允許 agent 與元件進行雙向的溝通。bridge 也允許 agents 之間互相溝通。\n\n### Dispatchers\n\ndispatcher 允許元件與 agnet 進行單向的溝通。dispatcher 也允許元件向 agnet 發送訊息。\n\n## 開銷\n\nAgents 透過使用 [bincode](https://github.com/servo/bincode) 序列化他們的訊息，來溝通。所以比起呼叫方法，他的效能花費比較高。除非計算的成本，或是跨元件計算的成本，比傳遞訊息的成本要高，否則 agnet 的方法儘量只有包含單純的邏輯運算。\n\n## 延伸閱讀\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 範例顯示了如何在 agnets 之間溝通。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/html/components.mdx",
    "content": "---\ndescription: 建立複雜元件層級與佈局\n---\n\n# Components\n\n## 基本\n\n任何實作 `Component` 的型別，都可以在 `html!` 的巨集中使用：\n\n```rust\nhtml!{\n    <>\n        // 沒有屬性\n        <MyComponent />\n\n        // 有屬性\n        <MyComponent prop1=\"lorem\" prop2=\"ipsum\" />\n\n        // 一次提供很多屬性\n        <MyComponent ..props />\n    </>\n}\n```\n\n## 巢狀\n\n只要元件的 `Properties` 中有 `children`，就可以傳遞子結點給元件。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <Container>\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n}\n```\n\n```rust title=\"container.rs\"\npub struct Container(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: Children,\n}\n\nimpl Component for Container {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n       html! {\n           <div id=\"container\">\n               { self.0.children.clone() }\n           </div>\n       }\n    }\n}\n```\n\n## 指定子結點的型別\n\n如果指定了子結點的型別，就可以使用或改變巢狀元件的屬性。下面的範例就是， `List` 元件包裹 `ListItem` 元件。另一個真實的範例是 `yew-router` 的原始碼。還有一個更進階的範例，請參考 Yew GitHub repo 中的 `nested-list` 範例。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n}\n```\n\n```rust title=\"list.rs\"\npub struct List(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\nimpl Component for List {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n        html!{{\n            for self.0.children.iter().map(|mut item| {\n                item.props.value = format!(\"item-{}\", item.props.value);\n                item\n            })\n        }}\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/html/elements.mdx",
    "content": "---\ndescription: HTML 與 SVG 元件都支援\n---\n\n# Elements\n\n## 標籤結構\n\n元件標籤都必須要是自封閉的標籤 `<... />` 或是跟開啟標籤對應的關閉標籤。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Open - Close-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"></div>\n}\n```\n\n<!--INVALID-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"> // <- 缺少關閉標籤\n}\n```\n\n<!--Self-Closing-->\n\n```rust\nhtml! {\n  <input id=\"my_input\" />\n}\n```\n\n<!--INVALID-->\n\n```rust\nhtml! {\n  <input id=\"my_input\"> // <- 缺少自封閉標籤語法\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n:::note\n為了方便起見，通常需要關閉標籤的元件，也都可以用自封閉標籤表示。例如，寫 `html! { <div class=\"placeholder\" /> }` 是合法的。\n:::\n\n## 子結點\n\n輕鬆寫出複雜巢狀的 HTML 與 SVG 架構：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--HTML-->\n\n```rust\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n}\n```\n\n<!--SVG-->\n\n```rust\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <feGaussianBlur stdDeviation=\"2\"/>\n                <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## Classes\n\n你很多方便的選項可以寫元件裡的 class：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Literal-->\n\n```rust\nhtml! {\n  <div class=\"container\"></div>\n}\n```\n\n<!--Multiple-->\n\n```rust\nhtml! {\n  <div class=\"container center-align\"></div>\n}\n```\n\n<!--Interpolated-->\n\n```rust\nhtml! {\n  <div class={format!(\"{}-container\", size)}></div>\n}\n```\n\n<!--Expression-->\n\n```rust\nhtml! {\n  <div class={self.classes()}></div>\n}\n```\n\n<!--Tuple-->\n\n```rust\nhtml! {\n  <div class={(\"class-1\", \"class-2\")}></div>\n}\n```\n\n<!--Vector-->\n\n```rust\nhtml! {\n  <div class={vec![\"class-1\", \"class-2\"]}></div>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## 監聽\n\n監聽器的屬性必須要傳入一個 `Callback` ，他封裝了閉包。callback 的內容取決於，當觸發監聽事件時，你希望應用程式有什麼反應：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Component Handler-->\n\n```rust\nstruct MyComponent {\n    link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => {\n                // 處理點擊事件\n            }\n        }\n    }\n\n    fn view(&self) -> Html {\n        // 從一個元件連結中，建立一個 callback 並在元件中處理他\n        let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Agent Handler-->\n\n```rust\nstruct MyComponent {\n    worker: Dispatcher<MyWorker>,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent {\n            worker: MyWorker::dispatcher()\n        }\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 從一個 worker 中建立一個 callback，並在其他的 context 中處理他\n        let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Other Cases-->\n\n```rust\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 建立一個臨時的 callback\n        let click_callback = Callback::from(|| {\n            ConsoleService::log(\"clicked!\");\n        });\n\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/html/introduction.mdx",
    "content": "---\ndescription: 用來產生 HTML 與 SVG 的巨集\nslug: /concepts/html\n---\n\n# 使用 html!\n\n`html!` 巨集可以讓你用 HTML 與 SVG 寫元件。如果你寫過 React 的 JSX（一種 JavaScript 的擴展，可以讓你在 JavaScript 中寫 HTML），應該會覺得這兩者十分相似。\n\n**重要提示**\n\n1. 在 `html!` 裡，只能有一個根結點（但你可以用 [Fragment 或是 Iterators](https://yew.rs/concepts/html/lists) 來繞過這個限制。）\n2. 空的 `html! {}` 是合法的，且他不會渲染任何東西在畫面上\n3. 字串必須被雙引號與大括號包裹住：`html! { \"Hello, World\" }`\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/html/lists.mdx",
    "content": "# Lists\n\n## Fragments\n\n`html!` 巨集裡必須只有一個根結點。為了可以繞過這個限制，將兩個以上的結點，用空的標籤包裹起來，是合法的：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Valid-->\n\n```rust\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n}\n```\n\n<!--Invalid-->\n\n```rust\n/* error: only one root html element allowed */\n\nhtml! {\n    <div></div>\n    <p></p>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## Iterators\n\nYew 支援兩種不同的方式，從 iterator 建構 html：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Syntax Type 1-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { self.props.items.iter().map(renderItem).collect::<Html>() }\n    </ul>\n}\n```\n\n<!--Syntax Type 2-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { for self.props.items.iter().map(renderItem) }\n    </ul>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/html/literals-and-expressions.mdx",
    "content": "# Literals & Expressions\n\n## Literals\n\n如果表達式中的型別有實作 `Display` ，他們會被轉換成字串，並在 DOM 中作為 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) （文字）結點。\n\n所有的文字都必須用 `{}` 括起來，因為文字是被當作表達式處理。這是 HTML 語法與 Yew 的語法中，最大的不同。\n\n```rust\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n}\n```\n\n## Expressions\n\n只要可以回傳 `Html`，你都可以在你的 HTML 中用 `{}` 插入表達式。\n\n```rust\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n}\n```\n\n通常把這些表達式與包裝成方法或閉包會比較好，可以提升可讀性：\n\n```rust\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/concepts/router.mdx",
    "content": "---\ndescription: Yew 的官方路由器\n---\n\n# 路由器\n\n[https://crates.io/crates/yew-router](https://crates.io/crates/yew-router)\n\n單頁應用程式（SPA）中的路由器，會依據 URL 來顯示不同的畫面。當連結被點擊後，路由器沒有預設要請求遠端的資源， 而是將 URL 設定導向應用程式中的有效路由。路由器會偵測 URL 被更改，然後決定要渲染什麼畫面。\n\n## 核心元素\n\n### Route\n\n包含一個字串，這個字串是網域名後的那串文字，並且可以選擇要不要將狀態存入 history api。\n\n### RouteService\n\n與瀏覽器溝通，存取路由。\n\n### RouteAgent\n\n擁有 RouteService 並且協調與更新，從應用程式邏輯造成的，或是從瀏覽器事件中造成的，路由的改變。\n\n### Switch\n\n`Switch` trait 用於讓 Route 在實作的 `trait` 之間來回轉換。\n\n### Router\n\nRouter 元件會與 `RouteAgent` 溝通，並且自動解析從 agent 到 switch 的 Routes，Routes 會在 render 的 屬性中被揭露，這個屬性會決定 switch 的結果如何被轉換成 `Html`。\n\n## 如何使用路由器\n\n首先，你要建立一個代表你的應用程式所有狀態的型別。特別注意，這個型別可以是 enum、struct 都可以，而且你可以透過在裡面實作 `Switch` 來巢狀其他項目\n\n然後你必須為你的型別 derive `Switch` 。對 enums 來說，每一個變數都必須宣告 `#[to = \"/some/route\"]`，或是如果你用 struct，那就要 struct 的外部宣告。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n  #[to=\"/\"]\n  Home\n}\n```\n\n特別注意，這個巨集會試著依序配對每個變數，所以如果有任何路由可能配對到兩著不同的 `to` 宣告，那會配對到第一個，而第二個就永遠不會被配對到。舉例來說，如果你定義以下的 `Switch` ，那路由將永遠只會配對到 `AppRoute::Home`。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/\"]\n  Home,\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n}\n```\n\n你還可以拿到 url 中的參數，透過在`#[to = \"\"]` 中宣告 `{}`。`{}` 代表下一個分隔符號（\"/\"、\"?\"、\"&\"、\"\\#\" ）之前， url 中的參數。`{*}` 表示取得直到後續字符匹配為止之間的變數，如果不存在任何字串，則它將匹配任何內容。 `{<number>}` 表示取得特定數量的的分隔符號之前的變數。（例如： `{2}` 會取得兩個分隔符號之前的變數。）\n\n對於有命名欄位的 struct 與 enum，你必須給出變數的名字，像是： `{user_name}` 或是 `{*:age}`。\n\nSwitch trait 可以協助取得比起字串要更有結構的變數。你可以實作 `Switch`，這樣你就可以得到特定結構的變數，而他會是一個 `unsize`。但如果這個 URL 無法被轉換，就會被視為沒有匹配。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/getting-started/build-a-sample-app.mdx",
    "content": "# 第一個簡單的 App\n\n首先，先建立一個新的 binary 專案：\n\n```bash\ncargo new --bin yew-app && cd yew-app\n```\n\n在依賴庫裡加入 `yew` 與 `wasm-bindgen`（最新的版號，請參考[這裡](https://docs.rs/yew)）\n\n```text title=\"Cargo.toml\"\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nauthors = [\"Yew App Developer <name@example.com>\"]\nedition = \"2018\"\n\n[dependencies]\nyew = \"0.16\"\nwasm-bindgen = \"0.2\"\n```\n\n將下面的模板複製進你的 `src/lib.rs` 檔案：\n\n```rust title=\"src/lib.rs\"\nuse wasm_bindgen::prelude::*;\nuse yew::prelude::*;\n\nstruct Model {\n    link: ComponentLink<Self>,\n    value: i64,\n}\n\nenum Msg {\n    AddOne,\n}\n\nimpl Component for Model {\n    type Message = Msg;\n    type Properties = ();\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        Self {\n            link,\n            value: 0,\n        }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::AddOne => self.value += 1\n        }\n        true\n    }\n\n    fn change(&mut self, _props: Self::Properties) -> ShouldRender {\n        // 如果有新的不同屬性，應該只能回傳 true\n        // 若是這個元件沒有任何屬性，那就可以只回傳 false\n        false\n    }\n\n    fn view(&self) -> Html {\n        html! {\n            <div>\n                <button onclick={self.link.callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n                <p>{ self.value }</p>\n            </div>\n        }\n    }\n}\n\n#[wasm_bindgen(start)]\npub fn run_app() {\n    App::<Model>::new().mount_to_body();\n}\n```\n\n模板會建置名叫 `Model` 的根元件 `Component`，Model 會顯示一個按鈕，當你按下按鈕時， `Model` 會更新自己的狀態。需要特別注意的是，在 `main()` 裡的 `App::<Model>::new().mount_to_body()`，他會啟動你的 app 並且掛載 `Model` 裡的 HTML 到 `<body>` 標籤中。如果你想要在啟動應用程式時，帶入動態的屬性，你可以改用 `App::<Model>::new().mount_to_body_with_props(..)`。\n\n最後，在你的專案，新增 `static` 資料夾，並新增 `index.html` 檔案到 static 裡。\n\n```bash\nmkdir static\n```\n\n```bash title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>Yew Sample App</title>\n        <script type=\"module\">\n            import init from \"./wasm.js\"\n            init()\n        </script>\n    </head>\n    <body></body>\n</html>\n```\n\n## 執行你的 App！\n\n使用 [`wasm-pack`](https://drager.github.io/wasm-pack/book/) 來執行專案是比較好的選擇。如果你還沒有做任何準備，先用`cargo install wasm-pack`安裝 `wasm-pack` ，然後用下面的指令，建置與開啟開發用伺服器：\n\n```bash\nwasm-pack build --target web --out-name wasm --out-dir ./static\n```\n\n`wasm-pack` 會在 `./static` 裡產生一個 bundle，裡面包含專案編成的 WebAssembly，以及 JavaScript 的包裹器，這些東西都會在你的專案執行時被載入。\n\n最後，用你最喜歡的網頁伺服器，去啟動在`./static` 底下的檔案。範例：\n\n```bash\ncargo +nightly install miniserve\nminiserve ./static --index index.html\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/getting-started/examples.mdx",
    "content": "# 透過範例學習\n\n我們有各種範例（都持續在維護中），建議你可以仔細閱讀他們，以了解如何使用各種不同的框架功能。當遇到問題或需要幫忙時，我們也很歡迎大家 pull-requests 或開 issues ♥️\n\n- [**Todo App \\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/todomvc)\n- [**Todo App \\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/todomvc)\n- [**Custom Components**](https://github.com/yewstack/yew/tree/v0.14.0/examples/custom_components)\n- [**Multi-threading \\(Agents\\) \\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/multi_thread)\n- [**Multi-threading \\(Agents\\) \\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/multi_thread)\n- [**Timer Service**](https://github.com/yewstack/yew/tree/v0.14.0/examples/timer)\n- [**Nested Components**](https://github.com/yewstack/yew/tree/v0.14.0/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/more/css.mdx",
    "content": "# CSS\n\n&lt;TODO&gt;\n\n有關 CSS 的支援與建議可以在這裡找到： [https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/more/debugging.mdx",
    "content": "# 除錯\n\n## Panics\n\n請使用 [`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook) crate ，他會用 Rust symbols 來做 stacktraces。注意，他跟 `cargo-web` 不相容。\n\n## Console Logging\n\n通常，Wasm 的網頁應用程式可以跟瀏覽器的 API 互操作，所以 `console.log` 這個 api 也不例外，你可以使用以下幾種方法：\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n這個 crate 整合了令人熟悉的 Rust `log` crate：\n\n```rust\n// 設定\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n}\n\n// 使用\nlog::info!(\"Update: {:?}\", msg);\n```\n\n### **\\`\\`**[**`ConsoleService`**](https://docs.rs/yew/0.13.2/yew/services/console/struct.ConsoleService.html)**\\`\\`**\n\nYew 包含了這個 service，而且如果 `\"services\"` 這個 feature 有被打開的話，你可以直接使用他：\n\n```rust\n// 使用\nConsoleService::info(format!(\"Update: {:?}\", msg).as_ref());\n```\n\n## Source Maps\n\n目前 Rust/Wasm 網頁應用程式，不對 source maps 第一線支援。當然，這件事在未來可能會改變，如果這裡寫的資訊不正確，或是事情有所變化，請建議我們修改這篇文件！\n\n### 最新資訊\n\n\\[2019 12 月\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 但還是有大量的工作要做。舉例還說，在工具方面，Emscripten \\(Binaryen\\) 與 wasm-pack \\(wasm-bindgen\\)，還不支援更新轉換他們的行為的 DWARF 資訊。\n\n\\[2020\\] [Rust Wasm 除錯指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸地，WebAssembly 的除錯還不夠完善。在大部分的 Unix 系統中，[DWARF](http://dwarfstd.org/) 被用來編碼除錯器需要提供的程式碼等級的資訊。還有一種在 Windows 上的編碼資訊。但現在還沒有跟 WebAssembly 等價。\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 除錯是一件棘手的事情，因為大部分的事情都不是掌握在這個工作群組中，而是依賴 WebAssembly 的標準，與瀏覽器的開發者工具如何實作。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/more/roadmap.mdx",
    "content": "---\ndescription: Yew 的版本紀錄\n---\n\n# Roadmap\n\n### 優先順序\n\n即將推出的新功能和重點開發方向的優先順序將由社群決定。在 2020 的春季，我們會發出一個開發者調查，收集專案方向的回饋。你可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到結果。\n\n:::note\n你可以在 Yew GitHub 追蹤我們主要的開發方向 [Project board](https://github.com/yewstack/yew/projects)\n:::\n\n### 重點 <a id=\"focuses\"></a>\n\n1. 需求最多的功能\n2. 產品準備\n3. 文件\n4. 痛點\n\n#### 需求最多的功能 <a id=\"top-requested-features\"></a>\n\n1. [函數式元件](https://github.com/yewstack/yew/projects/3)\n2. [元件函式庫](https://github.com/yewstack/yew/projects/4)\n3. 更好的狀態管理器\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n#### 產品準備\n\n- 提升 Yew 的測試覆蓋率\n- 減少二進位檔的大小\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n#### 文件\n\n- 建立教學文件\n- 簡化專案設定\n\n#### 痛點\n\n- [元件模板](https://github.com/yewstack/yew/issues/830)\n- Fetch API\n- Agents\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20/more/testing.mdx",
    "content": "---\ndescription: 測試你的專案\n---\n\n# 測試\n\n&lt;TODO&gt;\n\n## wasm_bindgen_test <a id=\"wasm_bindgen_test\"></a>\n\nRust Wasm 工作群組有維護一個 crate 叫作 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) ，他讓你可以在瀏覽器裡跑類似於用內建的巨集`#[test]`測試流程。 更多資訊可以參考 [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.20.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.20\",\n    \"description\": \"The label for version 0.20\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Using Basic Web Technologies In Yew\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew's Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may need in one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[function_component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[function_component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: '關於框架的底層細節'\n---\n\n# 內部底層的 library\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '優化與最佳實例'\nsidebar_label: Optimizations\ndescription: '加速你的專案'\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nTo avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications, it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component or just a big\nfunction that produces `Html`. Code that is shared between the crates containing different parts of\nthe application could be stored in a separate crate which the project depends on.\nIn the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and additionally render the component you are working on.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther, it is possible to optimize the size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading:\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[function_component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/server-side-rendering.md",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\ndescription: 'ComponentLink 與 Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[function_component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命週期'\ndescription: '元件，以及生命周期鉤子'\n---\n\nThe `Component` trait has a number of methods which need to be implemented; Yew will call these at different\nstages in the lifecycle of a component.\n\n## Lifecycle\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## Lifecycle Methods\n\n### Create\n\nWhen a component is created, it receives properties from its parent component and is stored within\nthe `Context<Self>` that is passed down to the `create` method. The properties can be used to\ninitialize the component's state and the \"link\" can be used to register callbacks or send messages to the component.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nThe `view` method allows you to describe how a component should be rendered to the DOM. Writing\nHTML-like code using Rust functions can become quite messy, so Yew provides a macro called `html!`\nfor declaring HTML and SVG nodes (as well as attaching attributes and event listeners to them) and a\nconvenient way to render child components. The macro is somewhat similar to React's JSX (the\ndifferences in programming language aside).\nOne difference is that Yew provides a shorthand syntax for properties, similar to Svelte, where instead of writing `onclick={onclick}`, you can just write `{onclick}`.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\nFor usage details, check out [the `html!` guide](concepts/html/introduction.mdx).\n\n### Rendered\n\nThe `rendered` component lifecycle method is called once `view` has been called and Yew has rendered\nthe results to the DOM, but before the browser refreshes the page. This method is useful when you\nwant to perform actions that can only be completed after the component has rendered elements. There\nis also a parameter called `first_render` which can be used to determine whether this function is\nbeing called on the first render, or instead a subsequent one.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nNote that this lifecycle method does not require implementation and will do nothing by default.\n:::\n\n### Update\n\nCommunication with components happens primarily through messages which are handled by the\n`update` lifecycle method. This allows the component to update itself\nbased on what the message was, and determine if it needs to re-render itself. Messages can be sent\nby event listeners, child components, Agents, Services, or Futures.\n\nHere is an example of what an implementation of `update` could look like:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nComponents may be re-rendered by their parents. When this happens, they could receive new properties\nand need to re-render. This design facilitates parent-to-child component communication by just\nchanging the values of a property. There is a default implementation that re-renders the component\nwhen props are changed.\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods but are only caused when trying to update\nthe same component after every render, when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it is often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample, you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to the component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: '父元件與子元件的溝通橋樑'\n---\n\n屬性讓子元件與父元件可以互相溝通。\nEvery component has an associated properties type which describes what is passed down from the parent.\nIn theory, this can be any type that implements the `Properties` trait, but in practice, there is no\nreason for it to be anything but a struct where each field represents a property.\n\n## Derive macro\n\nInstead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to\nautomatically generate the implementation instead.\nTypes for which you derive `Properties` must also implement `PartialEq`.\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they are set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: 'Refs'\ndescription: '外帶 DOM 的存取'\n---\n\n`ref` 關鍵字可以被使用在任何 HTML 的元素或是元件，用來得到那個物件附加的 DOM `Element`。這個可以在 view 生命周期方法之外，改變 DOM。\n\n對於要存取 canvas 元素，或滾動到頁面不同的區塊，很有幫助。\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\n語法可以這樣使用：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/agents.mdx",
    "content": "---\ndescription: Yew 的 Actor 系統\n---\n\n# Agents\n\nAgents 類似於 Angular 的 [Services](https://angular.io/guide/architecture-services) （但沒有依賴注入）而且提供 Tew 一個 [Actor Model](https://en.wikipedia.org/wiki/Actor_model). Agents 可以用來作為兩個元件間的路由訊息，而且與他們在元件間的層級關係獨立出來，所以他也可以用來作為一個全域的狀態，甚至可以用來減輕用來渲染 UI 畫面的主執行緒的大量運算任務。 未來，我們還規劃要讓 agents 幫忙 Yew 專案可以跨頁籤溝通。\n\n為了讓 agents 可以並行， Yew 使用了 [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命周期\n\n![Agent 生命周期](https://user-images.githubusercontent.com/42674621/79125224-b6481d80-7d95-11ea-8e6a-ab9b52d1d8ac.png)\n\n## Agents 的型別\n\n#### 範圍\n\n- Job - 在 UI 執行緒上，為每一個 bridge，新增一個 agent。這對於將「共享但獨立的行為」移出元件很有用。（待驗證）當工作結束，agent 會消失。\n- Context - Bridges 會建立並連接上 UI 執行緒上的 agent。這可以用來協調元件與其他 agent 之間的狀態。當沒有任何 bridge 連接上這個 agent，這個 agnet 就會消失。\n- Private - 與 Job 相同，但是是在自己的 web worker 上執行的。\n- Public - 與 Context 相同，但是是在自己的 web worker 上執行的。\n- Global （編寫中）\n\n## 在 Agents 與元件之間溝通\n\n### Bridges\n\nbridge 允許 agent 與元件進行雙向的溝通。bridge 也允許 agents 之間互相溝通。\n\n### Dispatchers\n\ndispatcher 允許元件與 agnet 進行單向的溝通。dispatcher 也允許元件向 agnet 發送訊息。\n\n## 開銷\n\nAgents 透過使用 [bincode](https://github.com/servo/bincode) 序列化他們的訊息，來溝通。所以比起呼叫方法，他的效能花費比較高。除非計算的成本，或是跨元件計算的成本，比傳遞訊息的成本要高，否則 agnet 的方法儘量只有包含單純的邏輯運算。\n\n## 延伸閱讀\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 範例顯示了如何在 agnets 之間溝通。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, function_component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[function_component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[function_component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[function_component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[function_component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[function_component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[function_component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[function_component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{function_component, html, Html};\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[function_component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Properties)'\ndescription: '父子元件通訊'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n屬性 (Properties) 通常被簡稱為 \"Props\"。\n\n:::\n\n屬性 (Properties) 本質上是 Yew 可以監視的元件參數。\n\n一個型別必須先實作 `Properties` 特徵才能被用作元件的屬性。\n\n## 響應性\n\nYew 在重新渲染時會在協調虛擬 DOM 時檢查 props 是否已更改，以了解是否需要重新渲染嵌套元件。這樣，Yew 可以被認為是一個非常響應式的框架，因為來自父元件的更改總是會向下傳播，視圖永遠不會與來自 props/狀態的資料不同步。\n\n:::tip\n\n如果您還沒有完成 [教程](../../tutorial)，請嘗試一下並自己測試這種響應性！\n\n:::\n\n## 派生巨集\n\nYew 提供了一個派生巨集來輕鬆地在結構體上實作 `Properties` 特徵。\n\n派生 `Properties` 的型別還必須實作 `PartialEq`，以便 Yew 可以進行資料比較。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函數元件中使用\n\n屬性 `#[function_component]` 允許可選地在函數參數中接收 Props。要提供它們，它們透過 `html!` 巨集中的屬性分配。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{props.is_loading.clone()}</> }\n}\n\n// 然後提供屬性\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{function_component, html, Html};\n\n\n\n\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 沒有要提供的屬性\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld />}\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生巨集欄位屬性\n\n派生 `Properties` 時，預設情況下所有欄位都是必需的。\n以下屬性允許您為屬性提供預設值，當父元件沒有設定它們時將使用這些預設值。\n\n:::tip\n屬性在 Rustdoc 生成的文件中不可見。您的屬性的文件字串應該提及屬性是否是可選的以及是否有特殊的預設值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` 特徵用欄位型別的預設值初始化屬性值。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading.clone() {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 然後像這樣使用預設值\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// 或者不覆蓋預設值\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 來初始化屬性值。`value` 可以是任何返回欄位型別的表達式。\n例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。表達式在建構屬性時被評估，並且沒有給出明確值時應用。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or(\"Bob\".to_string())]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// 然後像這樣使用預設值\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// 或者不覆蓋預設值\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n呼叫 `function` 來初始化屬性值。`function` 應該有簽名 `FnMut() -> T`，其中 `T` 是欄位型別。當沒有為該屬性給出明確值時，該函數被呼叫。\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\nfn create_default_name() -> String {\n    \"Bob\".to_string()\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// 然後像這樣使用預設值\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// 或者不覆蓋預設值\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的記憶體/速度開銷\n\n內部屬性是引用計數的。這意味著只有一個共享指標會沿著元件樹向下傳遞給 props。這節省了我們不得不複製整個 props 的成本，這可能很昂貴。\n\n:::tip\n使用 `AttrValue`，這是我們用於屬性值的自訂型別，而不是將它們定義為 String 或其他類似型別。\n:::\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建構屬性。\n\n巨集使用與結構體表達式相同的語法，除了您不能使用屬性或基本表達式（`Foo { ..base }`）。型別路徑可以直接指向 props（`path::to::Props`）或指向元件的關聯屬性（`MyComp::Properties`）。\n\n```rust\nuse yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or(AttrValue::from(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n#[function_component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = props! {\n        Props {} // 注意我們不需要指定 name 屬性\n    };\n    // highlight-end\n    html! {<HelloWorld ..pre_made_props />}\n}\n```\n\n## 評估順序\n\nProps 按指定的順序進行評估，如以下示例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n雖然幾乎任何 Rust 型別都可以作為屬性傳遞，但有一些應該避免的反模式。這些包括但不限於：\n\n1. 使用 `String` 型別而不是 `AttrValue`。 <br />\n   **為什麼不好？** `String` 複製成本很高。當屬性值與鉤子和回呼一起使用時，通常需要複製。`AttrValue` 是一個引用計數的字串 (`Rc<str>`) 或一個 `&'static str`，因此非常便宜複製。<br />\n   **注意**：`AttrValue` 內部是來自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看該包以了解更多資訊。\n2. 使用內部可變性。 <br />\n   **為什麼不好？** 內部可變性（例如 `RefCell`、`Mutex` 等）應該 _通常_ 避免使用。它可能會導致重新渲染問題（Yew 不知道狀態何時發生了變化），因此您可能需要手動強制重新渲染。就像所有事物一樣，它有其用武之地。請謹慎使用。\n3. 使用 `Vec<T>` 型別而不是 `IArray<T>`。 <br />\n   **為什麼不好？** `Vec<T>`，就像 `String` 一樣，複製成本也很高。`IArray<T>` 是一個引用計數的切片 (`Rc<[T]>`) 或一個 `&'static [T]`，因此非常便宜複製。<br />\n   **注意**：`IArray<T>` 可以從 [implicit-clone](https://crates.io/crates/implicit-clone) 匯入。查看該包以了解更多資訊。\n4. 您發覺可能的新內容。您是否遇到了一個希望早點了解清楚的邊緣情況？請隨時建立一個問題或向本文檔提供修復的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一個實驗性包，可讓您根據函數的參數動態建立 Props 結構體。如果屬性結構體永遠不會被重複使用，這可能會很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/html/components.mdx",
    "content": "---\ndescription: 建立複雜元件層級與佈局\n---\n\n# Components\n\n## 基本\n\n任何實作 `Component` 的型別，都可以在 `html!` 的巨集中使用：\n\n```rust\nhtml!{\n    <>\n        // 沒有屬性\n        <MyComponent />\n\n        // 有屬性\n        <MyComponent prop1=\"lorem\" prop2=\"ipsum\" />\n\n        // 一次提供很多屬性\n        <MyComponent ..props />\n    </>\n}\n```\n\n## 巢狀\n\n只要元件的 `Properties` 中有 `children`，就可以傳遞子結點給元件。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <Container>\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n}\n```\n\n```rust title=\"container.rs\"\npub struct Container(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: Children,\n}\n\nimpl Component for Container {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n       html! {\n           <div id=\"container\">\n               { self.0.children.clone() }\n           </div>\n       }\n    }\n}\n```\n\n## 指定子結點的型別\n\n如果指定了子結點的型別，就可以使用或改變巢狀元件的屬性。下面的範例就是， `List` 元件包裹 `ListItem` 元件。另一個真實的範例是 `yew-router` 的原始碼。還有一個更進階的範例，請參考 Yew GitHub repo 中的 `nested-list` 範例。\n\n```rust title=\"parent.rs\"\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n}\n```\n\n```rust title=\"list.rs\"\npub struct List(Props);\n\n#[derive(Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\nimpl Component for List {\n    type Properties = Props;\n\n    // ...\n\n    fn view(&self) -> Html {\n        html!{{\n            for self.0.children.iter().map(|mut item| {\n                item.props.value = format!(\"item-{}\", item.props.value);\n                item\n            })\n        }}\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/html/elements.mdx",
    "content": "---\ndescription: HTML 與 SVG 元件都支援\n---\n\n# Elements\n\n## 標籤結構\n\n元件標籤都必須要是自封閉的標籤 `<... />` 或是跟開啟標籤對應的關閉標籤。\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Open - Close-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"></div>\n}\n```\n\n<!--INVALID-->\n\n```rust\nhtml! {\n  <div id=\"my_div\"> // <- 缺少關閉標籤\n}\n```\n\n<!--Self-Closing-->\n\n```rust\nhtml! {\n  <input id=\"my_input\" />\n}\n```\n\n<!--INVALID-->\n\n```rust\nhtml! {\n  <input id=\"my_input\"> // <- 缺少自封閉標籤語法\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n:::note\n為了方便起見，通常需要關閉標籤的元件，也都可以用自封閉標籤表示。例如，寫 `html! { <div class=\"placeholder\" /> }` 是合法的。\n:::\n\n## 子結點\n\n輕鬆寫出複雜巢狀的 HTML 與 SVG 架構：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--HTML-->\n\n```rust\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n}\n```\n\n<!--SVG-->\n\n```rust\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <feGaussianBlur stdDeviation=\"2\"/>\n                <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## Classes\n\n你很多方便的選項可以寫元件裡的 class：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Literal-->\n\n```rust\nhtml! {\n  <div class=\"container\"></div>\n}\n```\n\n<!--Multiple-->\n\n```rust\nhtml! {\n  <div class=\"container center-align\"></div>\n}\n```\n\n<!--Interpolated-->\n\n```rust\nhtml! {\n  <div class={format!(\"{}-container\", size)}></div>\n}\n```\n\n<!--Expression-->\n\n```rust\nhtml! {\n  <div class={self.classes()}></div>\n}\n```\n\n<!--Tuple-->\n\n```rust\nhtml! {\n  <div class={(\"class-1\", \"class-2\")}></div>\n}\n```\n\n<!--Vector-->\n\n```rust\nhtml! {\n  <div class={vec![\"class-1\", \"class-2\"]}></div>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## 監聽\n\n監聽器的屬性必須要傳入一個 `Callback` ，他封裝了閉包。callback 的內容取決於，當觸發監聽事件時，你希望應用程式有什麼反應：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Component Handler-->\n\n```rust\nstruct MyComponent {\n    link: ComponentLink<Self>,\n}\n\nenum Msg {\n    Click,\n}\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        MyComponent { link }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::Click => {\n                // 處理點擊事件\n            }\n        }\n    }\n\n    fn view(&self) -> Html {\n        // 從一個元件連結中，建立一個 callback 並在元件中處理他\n        let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Agent Handler-->\n\n```rust\nstruct MyComponent {\n    worker: Dispatcher<MyWorker>,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent {\n            worker: MyWorker::dispatcher()\n        }\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 從一個 worker 中建立一個 callback，並在其他的 context 中處理他\n        let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--Other Cases-->\n\n```rust\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {\n        MyComponent\n    }\n\n    fn update(&mut self, _: Self::Message) -> ShouldRender {\n        false\n    }\n\n    fn view(&self) -> Html {\n        // 建立一個臨時的 callback\n        let click_callback = Callback::from(|| {\n            ConsoleService::log(\"clicked!\");\n        });\n\n        html! {\n            <button onclick={click_callback}>\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/html/introduction.mdx",
    "content": "---\ndescription: 用來產生 HTML 與 SVG 的巨集\nslug: /concepts/html\n---\n\n# 使用 html!\n\n`html!` 巨集可以讓你用 HTML 與 SVG 寫元件。如果你寫過 React 的 JSX（一種 JavaScript 的擴展，可以讓你在 JavaScript 中寫 HTML），應該會覺得這兩者十分相似。\n\n**重要提示**\n\n1. 在 `html!` 裡，只能有一個根結點（但你可以用 [Fragment 或是 Iterators](https://yew.rs/concepts/html/lists) 來繞過這個限制。）\n2. 空的 `html! {}` 是合法的，且他不會渲染任何東西在畫面上\n3. 字串必須被雙引號與大括號包裹住：`html! { \"Hello, World\" }`\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/html/lists.mdx",
    "content": "# Lists\n\n## Fragments\n\n`html!` 巨集裡必須只有一個根結點。為了可以繞過這個限制，將兩個以上的結點，用空的標籤包裹起來，是合法的：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Valid-->\n\n```rust\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n}\n```\n\n<!--Invalid-->\n\n```rust\n/* error: only one root html element allowed */\n\nhtml! {\n    <div></div>\n    <p></p>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n\n## Iterators\n\nYew 支援兩種不同的方式，從 iterator 建構 html：\n\n<!--DOCUSAURUS_CODE_TABS-->\n<!--Syntax Type 1-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { self.props.items.iter().map(renderItem).collect::<Html>() }\n    </ul>\n}\n```\n\n<!--Syntax Type 2-->\n\n```rust\nhtml! {\n    <ul class=\"item-list\">\n        { for self.props.items.iter().map(renderItem) }\n    </ul>\n}\n```\n\n<!--END_DOCUSAURUS_CODE_TABS-->\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/html/literals-and-expressions.mdx",
    "content": "# Literals & Expressions\n\n## Literals\n\n如果表達式中的型別有實作 `Display` ，他們會被轉換成字串，並在 DOM 中作為 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) （文字）結點。\n\n所有的文字都必須用 `{}` 括起來，因為文字是被當作表達式處理。這是 HTML 語法與 Yew 的語法中，最大的不同。\n\n```rust\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n}\n```\n\n## Expressions\n\n只要可以回傳 `Html`，你都可以在你的 HTML 中用 `{}` 插入表達式。\n\n```rust\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n}\n```\n\n通常把這些表達式與包裝成方法或閉包會比較好，可以提升可讀性：\n\n```rust\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/concepts/router.mdx",
    "content": "---\ndescription: Yew 的官方路由器\n---\n\n# 路由器\n\n[https://crates.io/crates/yew-router](https://crates.io/crates/yew-router)\n\n單頁應用程式（SPA）中的路由器，會依據 URL 來顯示不同的畫面。當連結被點擊後，路由器沒有預設要請求遠端的資源， 而是將 URL 設定導向應用程式中的有效路由。路由器會偵測 URL 被更改，然後決定要渲染什麼畫面。\n\n## 核心元素\n\n### Route\n\n包含一個字串，這個字串是網域名後的那串文字，並且可以選擇要不要將狀態存入 history api。\n\n### RouteService\n\n與瀏覽器溝通，存取路由。\n\n### RouteAgent\n\n擁有 RouteService 並且協調與更新，從應用程式邏輯造成的，或是從瀏覽器事件中造成的，路由的改變。\n\n### Switch\n\n`Switch` trait 用於讓 Route 在實作的 `trait` 之間來回轉換。\n\n### Router\n\nRouter 元件會與 `RouteAgent` 溝通，並且自動解析從 agent 到 switch 的 Routes，Routes 會在 render 的 屬性中被揭露，這個屬性會決定 switch 的結果如何被轉換成 `Html`。\n\n## 如何使用路由器\n\n首先，你要建立一個代表你的應用程式所有狀態的型別。特別注意，這個型別可以是 enum、struct 都可以，而且你可以透過在裡面實作 `Switch` 來巢狀其他項目\n\n然後你必須為你的型別 derive `Switch` 。對 enums 來說，每一個變數都必須宣告 `#[to = \"/some/route\"]`，或是如果你用 struct，那就要 struct 的外部宣告。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n  #[to=\"/\"]\n  Home\n}\n```\n\n特別注意，這個巨集會試著依序配對每個變數，所以如果有任何路由可能配對到兩著不同的 `to` 宣告，那會配對到第一個，而第二個就永遠不會被配對到。舉例來說，如果你定義以下的 `Switch` ，那路由將永遠只會配對到 `AppRoute::Home`。\n\n```rust\n#[derive(Switch)]\nenum AppRoute {\n  #[to=\"/\"]\n  Home,\n  #[to=\"/login\"]\n  Login,\n  #[to=\"/register\"]\n  Register,\n  #[to=\"/delete_account\"]\n  Delete,\n  #[to=\"/posts/{id}\"]\n  ViewPost(i32),\n  #[to=\"/posts/view\"]\n  ViewPosts,\n}\n```\n\n你還可以拿到 url 中的參數，透過在`#[to = \"\"]` 中宣告 `{}`。`{}` 代表下一個分隔符號（\"/\"、\"?\"、\"&\"、\"\\#\" ）之前， url 中的參數。`{*}` 表示取得直到後續字符匹配為止之間的變數，如果不存在任何字串，則它將匹配任何內容。 `{<number>}` 表示取得特定數量的的分隔符號之前的變數。（例如： `{2}` 會取得兩個分隔符號之前的變數。）\n\n對於有命名欄位的 struct 與 enum，你必須給出變數的名字，像是： `{user_name}` 或是 `{*:age}`。\n\nSwitch trait 可以協助取得比起字串要更有結構的變數。你可以實作 `Switch`，這樣你就可以得到特定結構的變數，而他會是一個 `unsize`。但如果這個 URL 無法被轉換，就會被視為沒有匹配。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/getting-started/build-a-sample-app.mdx",
    "content": "# 第一個簡單的 App\n\n首先，先建立一個新的 binary 專案：\n\n```bash\ncargo new --bin yew-app && cd yew-app\n```\n\n在依賴庫裡加入 `yew` 與 `wasm-bindgen`（最新的版號，請參考[這裡](https://docs.rs/yew)）\n\n```text title=\"Cargo.toml\"\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nauthors = [\"Yew App Developer <name@example.com>\"]\nedition = \"2018\"\n\n[dependencies]\nyew = \"0.16\"\nwasm-bindgen = \"0.2\"\n```\n\n將下面的模板複製進你的 `src/lib.rs` 檔案：\n\n```rust title=\"src/lib.rs\"\nuse wasm_bindgen::prelude::*;\nuse yew::prelude::*;\n\nstruct Model {\n    link: ComponentLink<Self>,\n    value: i64,\n}\n\nenum Msg {\n    AddOne,\n}\n\nimpl Component for Model {\n    type Message = Msg;\n    type Properties = ();\n    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {\n        Self {\n            link,\n            value: 0,\n        }\n    }\n\n    fn update(&mut self, msg: Self::Message) -> ShouldRender {\n        match msg {\n            Msg::AddOne => self.value += 1\n        }\n        true\n    }\n\n    fn change(&mut self, _props: Self::Properties) -> ShouldRender {\n        // 如果有新的不同屬性，應該只能回傳 true\n        // 若是這個元件沒有任何屬性，那就可以只回傳 false\n        false\n    }\n\n    fn view(&self) -> Html {\n        html! {\n            <div>\n                <button onclick={self.link.callback(|_| Msg::AddOne)}>{ \"+1\" }</button>\n                <p>{ self.value }</p>\n            </div>\n        }\n    }\n}\n\n#[wasm_bindgen(start)]\npub fn run_app() {\n    App::<Model>::new().mount_to_body();\n}\n```\n\n模板會建置名叫 `Model` 的根元件 `Component`，Model 會顯示一個按鈕，當你按下按鈕時， `Model` 會更新自己的狀態。需要特別注意的是，在 `main()` 裡的 `App::<Model>::new().mount_to_body()`，他會啟動你的 app 並且掛載 `Model` 裡的 HTML 到 `<body>` 標籤中。如果你想要在啟動應用程式時，帶入動態的屬性，你可以改用 `App::<Model>::new().mount_to_body_with_props(..)`。\n\n最後，在你的專案，新增 `static` 資料夾，並新增 `index.html` 檔案到 static 裡。\n\n```bash\nmkdir static\n```\n\n```bash title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>Yew Sample App</title>\n        <script type=\"module\">\n            import init from \"./wasm.js\"\n            init()\n        </script>\n    </head>\n    <body></body>\n</html>\n```\n\n## 執行你的 App！\n\n使用 [`wasm-pack`](https://drager.github.io/wasm-pack/book/) 來執行專案是比較好的選擇。如果你還沒有做任何準備，先用`cargo install wasm-pack`安裝 `wasm-pack` ，然後用下面的指令，建置與開啟開發用伺服器：\n\n```bash\nwasm-pack build --target web --out-name wasm --out-dir ./static\n```\n\n`wasm-pack` 會在 `./static` 裡產生一個 bundle，裡面包含專案編成的 WebAssembly，以及 JavaScript 的包裹器，這些東西都會在你的專案執行時被載入。\n\n最後，用你最喜歡的網頁伺服器，去啟動在`./static` 底下的檔案。範例：\n\n```bash\ncargo +nightly install miniserve\nminiserve ./static --index index.html\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/getting-started/examples.mdx",
    "content": "# 透過範例學習\n\n我們有各種範例（都持續在維護中），建議你可以仔細閱讀他們，以了解如何使用各種不同的框架功能。當遇到問題或需要幫忙時，我們也很歡迎大家 pull-requests 或開 issues ♥️\n\n- [**Todo App \\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/todomvc)\n- [**Todo App \\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/todomvc)\n- [**Custom Components**](https://github.com/yewstack/yew/tree/v0.14.0/examples/custom_components)\n- [**Multi-threading \\(Agents\\) \\(stdweb\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/multi_thread)\n- [**Multi-threading \\(Agents\\) \\(web_sys\\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/multi_thread)\n- [**Timer Service**](https://github.com/yewstack/yew/tree/v0.14.0/examples/timer)\n- [**Nested Components**](https://github.com/yewstack/yew/tree/v0.14.0/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/more/css.mdx",
    "content": "# CSS\n\n&lt;TODO&gt;\n\n有關 CSS 的支援與建議可以在這裡找到： [https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/more/debugging.mdx",
    "content": "# 除錯\n\n## Panics\n\n請使用 [`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook) crate ，他會用 Rust symbols 來做 stacktraces。注意，他跟 `cargo-web` 不相容。\n\n## Console Logging\n\n通常，Wasm 的網頁應用程式可以跟瀏覽器的 API 互操作，所以 `console.log` 這個 api 也不例外，你可以使用以下幾種方法：\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n這個 crate 整合了令人熟悉的 Rust `log` crate：\n\n```rust\n// 設定\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n}\n\n// 使用\nlog::info!(\"Update: {:?}\", msg);\n```\n\n### **\\`\\`**[**`ConsoleService`**](https://docs.rs/yew/0.13.2/yew/services/console/struct.ConsoleService.html)**\\`\\`**\n\nYew 包含了這個 service，而且如果 `\"services\"` 這個 feature 有被打開的話，你可以直接使用他：\n\n```rust\n// 使用\nConsoleService::info(format!(\"Update: {:?}\", msg).as_ref());\n```\n\n## Source Maps\n\n目前 Rust/Wasm 網頁應用程式，不對 source maps 第一線支援。當然，這件事在未來可能會改變，如果這裡寫的資訊不正確，或是事情有所變化，請建議我們修改這篇文件！\n\n### 最新資訊\n\n\\[2019 12 月\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 但還是有大量的工作要做。舉例還說，在工具方面，Emscripten \\(Binaryen\\) 與 wasm-pack \\(wasm-bindgen\\)，還不支援更新轉換他們的行為的 DWARF 資訊。\n\n\\[2020\\] [Rust Wasm 除錯指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸地，WebAssembly 的除錯還不夠完善。在大部分的 Unix 系統中，[DWARF](http://dwarfstd.org/) 被用來編碼除錯器需要提供的程式碼等級的資訊。還有一種在 Windows 上的編碼資訊。但現在還沒有跟 WebAssembly 等價。\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 除錯是一件棘手的事情，因為大部分的事情都不是掌握在這個工作群組中，而是依賴 WebAssembly 的標準，與瀏覽器的開發者工具如何實作。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/more/roadmap.mdx",
    "content": "---\ndescription: Yew 的版本紀錄\n---\n\n# Roadmap\n\n### 優先順序\n\n即將推出的新功能和重點開發方向的優先順序將由社群決定。在 2020 的春季，我們會發出一個開發者調查，收集專案方向的回饋。你可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到結果。\n\n:::note\n你可以在 Yew GitHub 追蹤我們主要的開發方向 [Project board](https://github.com/yewstack/yew/projects)\n:::\n\n### 重點 <a id=\"focuses\"></a>\n\n1. 需求最多的功能\n2. 產品準備\n3. 文件\n4. 痛點\n\n#### 需求最多的功能 <a id=\"top-requested-features\"></a>\n\n1. [函數式元件](https://github.com/yewstack/yew/projects/3)\n2. [元件函式庫](https://github.com/yewstack/yew/projects/4)\n3. 更好的狀態管理器\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n#### 產品準備\n\n- 提升 Yew 的測試覆蓋率\n- 減少二進位檔的大小\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n#### 文件\n\n- 建立教學文件\n- 簡化專案設定\n\n#### 痛點\n\n- [元件模板](https://github.com/yewstack/yew/issues/830)\n- Fetch API\n- Agents\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21/more/testing.mdx",
    "content": "---\ndescription: 測試你的專案\n---\n\n# 測試\n\n&lt;TODO&gt;\n\n## wasm_bindgen_test <a id=\"wasm_bindgen_test\"></a>\n\nRust Wasm 工作群組有維護一個 crate 叫作 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) ，他讓你可以在瀏覽器裡跑類似於用內建的巨集`#[test]`測試流程。 更多資訊可以參考 [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.21.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.21\",\n    \"description\": \"The label for version 0.21\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"Getting Started\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"Concepts\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Using Basic Web Technologies In Yew\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew's Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may needin one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"Advanced topics\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"More\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/children.mdx",
    "content": "---\ntitle: '子組件'\n---\n\n:::caution\n\n檢查和操作 `Children` 往往會導致應用程式中令人驚訝且難以解釋的行為。這可能導致邊緣情況，並且通常不會產生預期的結果。如果您嘗試操作 `Children`，則應考慮其他方法。\n\nYew 支援將 `Html` 用作子元件屬性的類型。如果您不需要 `Children` 或 `ChildrenRenderer`，則應使用 `Html` 作為子元件。它沒有 `Children` 的缺點，且效能開銷較低。\n\n:::\n\n## 一般用法\n\n*大多數情況下，*當允許元件具有子元件時，您不關心元件具有的子元件的類型。在這種情況下，下面的範例就足夠了。\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## 進階用法\n\n### 類型化子元件\n\n在您希望將一種類型的元件作為子元件傳遞給您的元件的情況下，您可以使用 `yew::html::ChildrenWithProps<T>`。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## 帶有屬性的巢狀子元件\n\n如果包含元件對其子元件進行了類型化，則可以存取和變更巢狀元件的屬性。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 枚舉類型的子元件\n\n當然，有時您可能需要將子元件限制為幾種不同的元件。在這些情況下，您必須更深入地了解 Yew。\n\n這裡使用 [`derive_more`](https://github.com/JelteF/derive_more) 來提供更好的人體工學。如果您不想使用它，您可以為每個變體手動實現 `From`。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 現在，我們實現 `Into<Html>`，以便 yew 知道如何渲染 `Item`。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### 可選類型的子元件\n\n您也可以具有特定類型的單一可選子元件：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... 页面内容\n            </div>\n        }\n    }\n}\n\n// 页面组件可以选择是否附带侧边栏：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // 附带侧边栏的页面\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // 不附带侧边栏的页面\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## 進一步閱讀\n\n- 有關此模式的真實範例，請查閱 yew-router 的原始程式碼。有關更高級的範例，請查看 yew 儲存庫中的[相關範例清單](https://github.com/yewstack/yew/tree/master/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '工作原理'\ndescription: '關於框架的底層細節'\n---\n\n# 底層庫的內部細節\n\n## `html!` 巨集的內部\n\n`html!` macro 會將使用類似 HTML 的自訂語法所編寫的程式碼轉換為有效的 Rust 程式碼。使用這個巨集對於開發 Yew 應用程式並不是必需的，但是是建議的。這個巨集產生的程式碼使用了 Yew 的公共函式庫 API，如果你願意的話，可以直接使用。請注意，有些方法是有意未記錄的，以避免意外的誤用。隨著 `yew-macro` 的每次更新，產生的程式碼將會更加高效，並且可以處理任何破壞性的更改，而不需要對 `html!` 語法進行很多（如果有的話）修改。\n\n由於 `html!` 巨集允許您以聲明式的風格編寫程式碼，因此您的 UI 佈局程式碼將與為頁面產生的 HTML 非常相似。隨著您的應用程式變得更加互動式，您的程式碼庫變得更大，這種方式變得越來越有用。與手動編寫所有操作 DOM 的程式碼相比，巨集會為您處理好這一切。\n\n使用 `html!` 巨集可能會讓人感到非常神奇，但它並沒有什麼可隱藏的。如果您對它的工作原理感到好奇，可以嘗試展開您程式中的 `html!` 巨集呼叫。有一個有用的指令叫做 `cargo expand`，它允許您查看 Rust 巨集的展開。 `cargo expand` 並不是預設隨 `cargo` 一起提供的，所以如果您還沒有安裝它，您需要使用 `cargo install cargo-expand` 來安裝它。 [Rust-Analyzer](https://rust-analyzer.github.io/) 也提供了一個[從IDE 中取得巨集輸出的機制](https://rust-analyzer.github.io/manual.html #expand-macro-recursively)。\n\n`html!` 巨集的輸出通常非常簡潔！這是一個功能：機器產生的程式碼有時可能會與應用程式中的其他程式碼衝突。為了防止問題，`proc_macro` 遵循了「衛生」規則。一些例子包括：\n\n1. 為了確保正確引用 Yew 套件，巨集產生的程式碼中使用 `::yew::<module>`，而不是直接使用 `yew::<module>`。這也是為什麼呼叫 `::alloc::vec::Vec::new()` 而不是直接呼叫 `Vec::new()`。\n2. 由於可能有 trait 方法名稱衝突，使用 `<Type as Trait>` 來確保我們使用的是正確的 trait 成員。\n\n## 什麼是虛擬 DOM？\n\nDOM（\"文件物件模型\"）是由瀏覽器管理的 HTML 內容的表示。 \"虛擬\" DOM 只是 DOM 的一個記憶體中的副本。管理虛擬 DOM 會導致更高的記憶體開銷，但可以透過避免或延遲使用瀏覽器 API 來實現批次和更快的讀取。\n\n在記憶體中擁有 DOM 的副本對於促進使用聲明式 UI 的函式庫是有幫助的。與需要特定程式碼來描述如何根據使用者事件修改 DOM 不同，程式庫可以使用一種通用的方法來進行 DOM \"diffing\"。當 Yew 元件更新並希望更改其呈現方式時，Yew 庫將建立虛擬 DOM 的第二個副本，並直接將其與鏡像當前螢幕上的內容的虛擬 DOM 進行比較。兩者之間的 \"diff\"（差異）可以分解為增量更新，並與瀏覽器 API 一起應用。一旦更新應用，舊的虛擬 DOM 副本將被丟棄，新的副本將被保存以供將來的差異檢查。\n\n這種 \"diff\" 演算法可以隨著時間的推移進行最佳化，以提高複雜應用程式的效能。由於 Yew 應用程式是透過 WebAssembly 運行的，我們相信 Yew 在未來採用更複雜的演算法方面具有競爭優勢。\n\nYew 的虛擬 DOM 與瀏覽器 DOM 不完全一一對應。它還包括用於組織 DOM 元素的 \"列表\" 和 \"元件\"。列表可以簡單地是元素的有序列表，但也可以更強大。透過為每個清單元素新增 \"key\" 註解，應用程式開發人員可以幫助 Yew 進行額外的最佳化，以確保在清單變更時，計算差異更新所需的工作量最小。同樣，元件提供了自訂邏輯，指示是否需要重新渲染，以幫助提高效能。\n\n## Yew 調度器和元件範圍的事件循環\n\n_貢獻文件 - 深入解釋 `yew::scheduler` 和 `yew::html::scope` 的工作原理_\n\n## 進一步閱讀\n\n- [Rust 手冊中關於巨集的更多資訊](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` 的更多資訊](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` 的 API 文件](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/immutable.mdx",
    "content": "---\ntitle: '不可變型別'\ndescription: 'Yew 的不可變資料結構'\n---\n\n## 什麼是不可變型別？\n\n這些類型是您可以實例化但永遠不會更改值的類型。為了更新值，您必須實例化一個新值。\n\n## 為什麼使用不可變型別？\n\n與 React 一樣，屬性是從祖先傳播到子代的。這意味著屬性在每個元件更新時必須存在。這就是為什麼屬性應該——理想情況下——很容易克隆。為了實現這一點，我們通常將事物包裝在 `Rc` 中。\n\n不可變類型非常適合保存屬性的值，因為它們可以在從組件傳遞到組件時以很低的成本克隆。\n\n## 常見的不可變型別\n\nYew 推薦使用來自 `implicit-clone` crate 的以下不可變型別：\n\n- `IString`（在 Yew 中別名為 `AttrValue`）- 用於字串而不是 `String`\n- `IArray<T>` - 用於陣列/向量而不是 `Vec<T>`\n- `IMap<K, V>` - 用於映射而不是 `HashMap<K, V>`\n\n這些型別是引用計數（`Rc`）或靜態引用，使它們的克隆成本非常低。\n\n## 進一步閱讀\n\n- [不可變範例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '優化 & 最佳實踐'\nsidebar_label: Optimizations\ndescription: '讓您的應用程式獲得最佳效能'\n---\n\n## 使用智慧指針\n\n**注意：如果您對本節中使用的某些術語感到困惑，Rust 手冊中有一個有用的[關於智慧型指針的章節](https://doc.rust-lang.org/book/ch15-00- smart-pointers.html)。 **\n\n為了避免在重新渲染時克隆大量資料以創建 props，我們可以使用智慧指針，只克隆對資料的引用而不是資料本身。如果您在props 和子組件中傳遞與相關數據的引用而不是實際數據，您可以避免在需要修改數據的子組件中克隆任何數據，您可以使用`Rc::make_mut` 來克隆並獲得要更改的數據的可變引用。\n\n這在 `Component::changed` 中帶來了更多好處，可以確定 prop 變更是否需要元件重新渲染。這是因為可以比較指標位址（即資料儲存在機器記憶體中的位置）而不是資料的值；如果兩個指標指向相同的數據，則它們指向的資料的值必須相同。請注意，反之可能不成立！即使兩個指標位址不同，底層資料仍可能相同 - 在這種情況下，您應該比較底層資料。\n\n要進行此比較，您需要使用 `Rc::ptr_eq` 而不僅使用 `PartialEq`（在使用相等運算子 `==` 比較資料時自動使用）。 Rust 文件有關於 `Rc::ptr_eq` 的[更多細節](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\n這種最佳化對於不實作 `Copy` 的資料類型最有用。如果您可以廉價地複製數據，則沒有必要將其放在智慧指標後面。對於可能是資料密集的結構，如 `Vec`、`HashMap` 和 `String`，使用智慧指標可能會帶來效能改進。\n\n如果數值從不被子元件更新，則此最佳化效果最佳，如果父元件很少更新，則效果更佳。這使得 `Rc<_>` 是在純元件中包裝屬性值的一個不錯的選擇。\n\n但是，必須注意，除非您需要在子元件中自己克隆數據，否則這種最佳化不僅是無用的，而且還增加了不必要的引用計數成本。 Yew 中的 props 已經是引用計數的，內部不會發生資料克隆。\n\n## 渲染函數\n\n出於程式碼可讀性的原因，將 `html!` 的部分重複程式碼遷移到專門分割出來的函數中通常是有意義的。這不僅使您的程式碼更易讀，減少了程式碼縮進，而且還鼓勵良好的設計模式——特別是圍繞構建可組合應用程序，這些函數可以在多個地方調用，從而減少程式碼量。\n\n## 純組件\n\n純組件是不會改變其狀態的元件，只顯示內容並將訊息傳播到普通的可變組件。它們與視圖函數的不同之處在於，它們可以在`html!` 巨集中使用元件語法（`<SomePureComponent />`）而不是表達式語法（`{some_view_function()}`），並且根據其實現，它們可以被記憶化（這意味著一旦調用函數，其值就會被“保存”，因此如果多次使用相同的參數調用它，則不必重新計算其值，只需從第一個函數調用返回保存的值）- 防止相同的props 重新渲染。 Yew 在內部比較 props，因此僅在 props 更改時重新渲染 UI。\n\n## 使用工作區減少編譯時間\n\nYew 的最大缺點是編譯所需的時間很長。編譯專案所需的時間似乎與傳遞給 `html!` 巨集的程式碼數量有關。對於較小的項目，這似乎不是什麼問題，但對於較大的應用程序，將程式碼拆分到多個 crate 中以最小化編譯器為應用程式所做的工作量是有意義的。\n\n一種可能的方法是使您的主 crate 處理路由/頁面選擇，然後為每個頁面建立一個不同的 crate，其中每個頁面可以是不同的元件或只是產生 `Html` 的大函數。儲存在包含應用程式不同部分的 crate 之間的程式碼可以儲存在專案依賴的單獨 crate 中。在最理想的情況下，您從每次編譯時重新建置所有程式碼到僅重新建置主 crate 和一個頁面 crate。在最壞的情況下，如果您在「common」 crate 中編輯了某些內容，您將回到起點：編譯依賴於該常用共享 crate 的所有程式碼，這可能是其他所有內容。\n\n如果您的主crate 太重，或者您想快速迭代一個深度巢狀的頁面（例如。在另一個頁面上渲染的頁面），您可以使用範例crate 建立主頁面的簡化實現，並額外渲染您正在處理的組件。\n\n## 減少二進位檔案大小\n\n- 優化 Rust 程式碼\n- `cargo.toml`（定義發布設定檔）\n- 使用 `wasm-opt` 最佳化 wasm 程式碼\n\n**注意：有關減小二進位檔案大小的更多信息，請參閱[Rust Wasm 手冊](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code -size)。 **\n\n### Cargo.toml\n\n可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用設定來配置發佈建置為更小。\n\n```toml, title=Cargo.toml\n[profile.release]\n# 讓二進位檔案尺寸更小些\npanic = 'abort'\n# 優化整個程式碼庫（優化更好，但建置速度也會更慢）\ncodegen-units = 1\n# 優化尺寸（更激進的做法）\nopt-level = 'z'\n# 優化尺寸\n# opt-level = 's'\n# 使用程式整體分析時進行連結時優化\nlto = true\n```\n\n### 開發版 Cargo 配置\n\n您還可以從 Rust 和 cargo 的實驗性開發版功能中獲得額外的好處。若要使用 `trunk` 的開發版工具鏈，請設定 `RUSTUP_TOOLCHAIN=\"nightly\"` 環境變數。然後，您可以在 `.cargo/config.toml` 中配置不穩定的 rustc 功能。請參考[不穩定功能]的文檔，特別是關於[`build-std`]和[`build-std-features`]的部分，以了解配置。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# 需要 rust-src 組件。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不穩定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n開發版 Rust 編譯器可能包含錯誤，例如[這個例子](https://github.com/yewstack/yew/issues/2696)，需要偶爾注意和調整。請謹慎使用這些實驗性選項。\n:::\n\n### wasm-opt\n\n此外，可以最佳化 `wasm` 程式碼的大小。\n\nRust Wasm 手冊中有關於減少 Wasm 二進位檔案大小的部分：[縮小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用 `wasm-pack`，預設會最佳化發佈建置中的 `wasm` 程式碼\n- 直接在 `wasm` 檔案上使用 `wasm-opt`\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 在 yew/examples/ 中 'minimal' 範例的建置大小\n\n注意：`wasm-pack` 結合了 Rust 和 Wasm 程式碼的最佳化。在此範例中，`wasm-bindgen` 未經任何 Rust 大小最佳化。\n\n| 工具鏈                      | 大小  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## 進一步閱讀\n\n- [Rust 手冊中關於智慧型指標的章節](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm 手冊中關於減小二進位檔案大小的資訊](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust 設定檔的文件](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen 專案](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/portals.mdx",
    "content": "---\ntitle: '傳送門 (Portals)'\ndescription: '將內容渲染到 DOM 樹外的節點'\n---\n\n## 什麼是 Portal？\n\n傳送門 (Portal) 提供了一種將子元素渲染到父元件的 DOM 層次結構以外的 DOM 節點的方法。 `yew::create_portal(child, host)` 傳回一個 `Html` 值，它將 `child` 渲染為 `host` 元素的子元素，而不是在其父元件的層次結構下。\n\n## 用法\n\n傳送門的典型用途包括模態對話框和懸停卡片，以及更多技術應用，例如控制元素的[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API /Element/shadowRoot) 的內容，將樣式表附加到周圍文檔的`<head>` 中，以及在`<svg>` 的中央`<defs>` 元素中收集引用的元素。\n\n請注意，`yew::create_portal` 是一個低階建置區塊。庫應該使用它來實現更高級的 API，然後應用程式可以使用這些 API。例如，這裡是一個簡單的模態對話框，它將其 `children` 渲染到 `yew` 以外的元素中，該元素由 `id=\"modal_host\"` 標識。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## 事件處理\n\n傳送門內部元素上發出的事件遵循虛擬 DOM 冒泡。也就是說，如果傳送門被渲染為元素的子元素，那麼該元素上的事件監聽器將捕捉從傳送門內部分發出的事件，即使傳送門將其內容渲染在實際 DOM 中的不相關位置。\n\n這使開發人員無需關心他們使用的組件是使用傳送門實現的還是沒有使用傳送門實現的。無論如何，其子元素上觸發的事件都會冒泡。\n\n已知問題是，從傳送門到 **關閉** 的 shadow root 的事件將被分發兩次，一次針對 shadow root 內部的元素，一次針對宿主元素本身。請記住，**打開** 的 shadow root 可以正常工作。如果這影響到您，請隨時提交錯誤報告。\n\n## 進一步閱讀\n\n- [傳送門範例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: '服務端渲染'\ndescription: '在服務端渲染 Yew 元件。 '\n---\n\n# 服務端渲染 (Server-Side Rendering)\n\n預設情況下，Yew 元件在客戶端渲染。當使用者造訪一個網站時，伺服器會傳送一個骨架 HTML 文件，不包含任何實際內容，以及一個 WebAssembly 套件給瀏覽器。所有內容都由 WebAssembly 套件在客戶端渲染。這被稱為客戶端渲染。\n\n這種方法對於大多數網站來說都是有效的，但有一些注意事項：\n\n1. 使用者在整個 WebAssembly 套件下載並完成初始渲染之前將看不到任何內容。這可能會導致在緩慢的網路上用戶體驗不佳。\n2. 有些搜尋引擎不支援動態渲染的網頁內容，而那些支援的搜尋引擎通常會將動態網站排名較低。\n\n為了解決這些問題，我們可以在服務端渲染我們的網站。\n\n## 工作原理\n\nYew 提供了一個 `ServerRenderer` 來在服務端渲染頁面。\n\n要在服務端渲染Yew 元件，您可以使用`ServerRenderer::<App>::new()` 建立一個渲染器，並呼叫`renderer.render().await` 將`<App />` 渲染為一個`String`。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// 我們在使用 `flavor = \"current_thread\"` 以確保這個範例可以在 CI 中的 WASM 環境運作,\n// 如果你希望使用多執行緒的話，可以使用預設的 `#[tokio::main]` 宏\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // 列印: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## 組件生命週期\n\n與客戶端渲染不同，元件的生命週期在服務端渲染時會有所不同。\n\n在元件成功第一次渲染為 `Html` 之前，除了 `use_effect` (和 `use_effect_with`) 之外的所有鉤子都會正常運作。\n\n:::caution 瀏覽器介面不可用！\n\n瀏覽器相關的接口，如 `web_sys`，在元件在服務端渲染時是不可用的。如果您嘗試使用它們，您的應用程式將會崩潰。您應該將需要這部分邏輯隔離在 `use_effect` 或 `use_effect_with` 中，因為在服務端渲染時它們無法也不應執行。\n\n:::\n\n:::danger 結構化組件\n\n儘管可以在服務端渲染時使用結構化元件，但是在客戶端安全邏輯（如函數元件的`use_effect` 鉤子）和生命週期事件之間沒有明確的邊界，並且生命週期事件的呼叫順序與客戶端不同。\n\n此外，結構化元件將繼續接受訊息，直到所有子元件都被渲染並呼叫了 `destroy` 方法。開發人員需要確保不會將可能傳遞給元件的訊息連結到呼叫瀏覽器介面的邏輯。\n\n在設計支援服務端渲染的應用程式時，請盡量使用函數元件，除非您有充分的理由不這樣做。\n\n:::\n\n## 服務端渲染期間的資料獲取\n\n資料取得是服務端渲染和水合（hydration）期間的困難之一。\n\n在傳統做法中，當一個元件渲染時，它會立即可用（輸出一個虛擬 DOM 以進行渲染）。當元件不需要取得任何資料時，這種方式是有效的。但是如果元件在渲染時想要取得一些資料會發生什麼事呢？\n\n過去，Yew 沒有機制來檢測組件是否仍在取得資料。資料擷取用戶端負責實作一個解決方案，以偵測在初始渲染期間請求了什麼，並在請求完成後觸發第二次渲染。伺服器會重複這個過程，直到在回傳回應之前沒有在渲染期間添加更多的掛起請求。\n\n這不僅浪費了CPU 資源，因為重複渲染元件，而且資料用戶端還需要提供一種方法，在水合過程中使在服務端獲取的資料可用，以確保初始渲染返回的虛擬DOM 與服務端渲染的DOM樹一致，這可能很難實現。\n\nYew 採用了不同的方法，透過 `<Suspense />` 來解決這個問題。\n\n`<Suspense />` 是一個特殊的元件，當在客戶端使用時，它提供了一種在元件獲取資料（掛起）時顯示一個回退UI 的方法，並在資料獲取完成後恢復到正常UI。\n\n當應用程式在服務端渲染時，Yew 會等待元件不再掛起，然後將其序列化到字串緩衝區中。\n\n在水合過程中，`<Suspense />` 組件中的元素保持未水合狀態，直到所有子組件不再掛起。\n\n透過這種方法，開發人員可以輕鬆建立一個準備好進行服務端渲染的、與客戶端無關的應用程序，並進行資料擷取。\n\n## 渲染 `<head>` 標籤\n\nSSR 中的一個常見需求是渲染動態 `<head>` 內容（例如 `<title>`、`<meta>`），使爬蟲和社群預覽在首次載入時能看到正確的中繼資料。\n\n`ServerRenderer` 只渲染元件樹（通常對應文件的 body 部分），無法存取 `<head>`。因此，head 標籤必須**在伺服器端、Yew 之外**產生，並在傳送給客戶端之前拼接到 HTML 範本中。\n\n[`ssr_router` 範例](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) 展示了這個模式：伺服器從請求 URL 識別路由，產生適當的 `<title>` 和 `<meta>` 標籤，並將它們注入到 Trunk 產生的 `index.html` 的 `</head>` 之前。\n\n:::info\n\n如需完全相容 SSR 的第三方解決方案，請使用 [Bounce 的 `<Helmet/>` 元件](https://docs.rs/bounce/latest/bounce/helmet/index.html)。\n\n:::\n\n## SSR 水合（SSR Hydration）\n\n水合是將 Yew 應用程式連接到服務端產生的 HTML 檔案的過程。預設情況下，`ServerRender` 會列印可水合的 HTML 字串，其中包含額外的資訊以便於水合。當呼叫 `Renderer::hydrate` 方法時，Yew 不會從頭開始渲染，而是將應用程式產生的虛擬 DOM 與伺服器渲染器產生的 HTML 字串進行協調。\n\n:::caution\n\n要成功對由 `ServerRenderer` 建立的 HTML 標記進行水合，用戶端必須產生一個虛擬 DOM 佈局，它與用於 SSR 的佈局完全匹配，包括不包含任何元素的元件。如果您有任何只在一個實作中有用的元件，您可能想要使用 `PhantomComponent` 來填入額外元件的位置。\n:::\n\n:::warning\n\n只有在瀏覽器初始渲染 SSR 輸出（靜態 HTML）後，真實 DOM 與預期 DOM 相符時，水合才能成功。如果您的 HTML 不符合規範，水合可能會失敗。瀏覽器可能會更改不正確的 HTML 的 DOM 結構，導致實際 DOM 與預期 DOM 不同。例如，[如果您有一個沒有`<tbody>` 的`<table>`，瀏覽器可能會向DOM 添加一個`<tbody>`](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## 水合期間的組件生命週期\n\n在水合期間，元件在創建後安排了 2 次連續的渲染。任何效果都是在第二次渲染完成後調用的。確保您的元件的渲染函數沒有副作用是很重要的。它不應該改變任何狀態或觸發額外的渲染。如果您的元件目前改變狀態或觸發額外的渲染，請將它們移到 `use_effect` 鉤子中。\n\n在水合過程中，可以使用結構化元件進行服務端渲染，視圖函數將在渲染函數之前被調用多次。直到呼叫渲染函數之前，DOM 被認為是未連接的，您應該防止在呼叫 `rendered()` 方法之前存取渲染節點。\n\n## 範例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // 對 body 元素下的所有內容進行水合，並移除可能有的任何尾隨元素。\n    renderer.hydrate();\n}\n```\n\n範例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n範例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## 單線程模式\n\nYew 支援以單一執行緒進行服務端渲染，透過 `yew::LocalServerRenderer`。這種模式適用於像 WASI 這樣的單執行緒環境。\n\n```rust\n// 使用 `wasm32-wasip1` 或 `wasm32-wasip2` 目標建置。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n範例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n如果您使用 `wasm32-unknown-unknown` 目標建立 SSR 應用程序，您可以使用 `not_browser_env` 功能標誌來停用 Yew 內部對特定於瀏覽器的 API 的存取。這在像 Cloudflare Worker 這樣的無伺服器平台上非常有用。\n:::\n\n:::caution\n\n服務端渲染目前是實驗性的。如果您發現了一個 bug，[請在 GitHub 回饋](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回呼函數 (Callbacks)'\n---\n\n## 回呼函數 (Callbacks)\n\n回調函數是用於在 Yew 中與服務、代理和父元件進行通訊的。在內部，它們的類型只是 `Fn` 包裝在 `Rc` 中，以允許它們被克隆。\n\n它們有一個 `emit` 函數，該函數以其 `<IN>` 類型作為參數，並將其轉換為其目標期望的訊息。如果父元件中的回呼函數作為 props 提供給子元件，子元件可以在其 `update` 生命週期鉤子中呼叫回呼函數的 `emit` 函數，以將訊息傳回其父元件。在 `html!` 巨集中作為 props 提供的閉包或函數會自動轉換為回呼函數。\n\n一個簡單的回呼函數的使用可能如下所示：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\n這個函數傳遞給 `callback` 必須永遠帶有一個參數。例如，`onclick` 處理程序需要一個接受 `MouseEvent` 類型參數的函數。然後處理程序可以決定應該發送什麼類型的消息給組件。這個訊息無條件地被安排在下一個更新循環中。\n\n如果你需要一個回呼函數，它可能不需要引起更新，請使用 `batch_callback`。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 相關範例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高階組件'\n---\n\n在某些情況下，結構組件不直接支援某些功能（例如 Suspense），或使用某些功能需要大量的樣板程式碼（例如 Context）。\n\n在這些情況下，建議建立高階組件的函數組件。\n\n## 高階組件定義\n\n高階元件是不添加任何新 HTML 的元件，只是包裝其他元件以提供額外功能。\n\n### 範例\n\n對 Context (上下文) 掛鉤並將其傳遞給結構組件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '簡介'\ndescription: 'Yew 中的元件'\n---\n\n## 什麼是元件？\n\n組件是 Yew 的構建塊。它們管理內部狀態並可以將元素渲染到 DOM 中。透過為類型實作 `Component` trait 來建立元件。\n\n## 編寫元件標記\n\nYew 使用虛擬 DOM 將元素渲染到 DOM 中。虛擬 DOM 樹可以透過使用 `html!` 巨集來建構。 `html!` 使用的語法類似 HTML，但並不相同。規則也更嚴格。它還提供了條件渲染和使用迭代器渲染清單等超能力。\n\n:::info\n[了解更多關於 `html!` 宏，如何使用它以及它的語法](concepts/html/introduction.mdx)\n:::\n\n## 將資料傳遞給元件\n\nYew 元件使用 _props_ 在父元件和子元件之間通訊。父元件可以將任何資料作為 props 傳遞給其子元件。 Props 類似於 HTML 屬性，但可以將任何 Rust 類型作為 props 傳遞。\n\n:::info\n[了解更多關於 props 的內容](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n對於除了父/子通信之外的其他通信，請使用 [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命週期'\ndescription: '元件及其生命週期鉤子'\n---\n\n`Component` trait 有許多方法需要實作；Yew 會在元件的生命週期的不同階段呼叫這些方法。\n\n## 生命週期\n\n:::important 改進文檔\n`為文件做貢獻：` [新增自訂生命週期的組件範例](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命週期方法\n\n### Create\n\n當元件被建立時，它會從其父元件接收屬性，並儲存在傳遞給 `create` 方法的 `Context<Self>` 中。這些屬性可以用來初始化元件的狀態，而 \"link\" 可以用來註冊回呼或傳送訊息給元件。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具體實現\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法可讓您描述元件應該如何呈現到 DOM 中。使用Rust 函數編寫類似HTML 的程式碼可能會變得非常混亂，因此Yew 提供了一個名為`html!` 的宏，用於聲明HTML 和SVG 節點（以及將屬性和事件監聽器附加到它們）以及一種方便的方法來渲染子元件。這個宏在某種程度上類似於 React 的 JSX（除了程式語言的差異）。一個不同之處是 Yew 提供了一種類似 Svelte 的屬性的簡寫語法，其中您可以只寫 `{onclick}`，而不用寫 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n就使用上的說明，請查看 [html! 指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 元件生命週期方法在 `view` 被調用並且 Yew 已經將結果渲染到 DOM 中後調用，但在瀏覽器刷新頁面之前。當您想要執行只能在元件渲染元素後完成的操作時，此方法非常有用。還有一個名為 `first_render` 的參數，可以用來確定此函數是在第一次渲染時調用，還是在後續渲染時調用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n請注意，此生命週期方法不需要實現，並且預設不會執行任何操作。\n:::\n\n### Update\n\n與組件的通訊主要透過訊息進行，這些訊息由 `update` 生命週期方法處理。這允許元件根據訊息更新自身，並確定是否需要重新渲染自身。訊息可以由事件監聽器、子元件、Agents、Services 或 Futures 傳送。\n\n下面是 `update` 的實作範例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 重新渲染\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具體實現\n        }\n    }\n\n}\n```\n\n### Changed\n\n元件可能會被其父元件重新渲染。當這種情況發生時，它們可能會接收新的屬性並需要重新渲染。這種設計透過僅更改屬性的值來促進父子組件之間的通訊。當屬性更改時，有一個預設實作會重新渲染元件。\n\n### Destroy\n\n元件從 DOM 卸載後，Yew 會呼叫 `destroy` 生命週期方法；如果您需要在元件被銷毀之前執行清理操作，這是必要的。此方法是可選的，預設不執行任何操作。\n\n### 無限循環\n\n無限循環在 Yew 的生命週期方法中是可能的，但只有在嘗試在每次渲染後更新相同的元件時，當更新也要求重新渲染元件時才會發生。\n\n下面是一個簡單的範例：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // 我們總是請求在任何訊息上重新渲染\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // 無論渲染什麼都不重要\n        Html::default()\n        }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // 請求使用此新訊息更新元件\n        ctx.link().send_message(());\n    }\n}\n```\n\n讓我們看看這裡發生了什麼：\n\n1. 使用 `create` 函數建立元件。\n2. 呼叫 `view` 方法，以便 Yew 知道要渲染到瀏覽器 DOM 中的內容。\n3. 呼叫 `rendered` 方法，使用 `Context` 連結安排更新訊息。\n4. Yew 完成後渲染階段。\n5. Yew 檢查已排程的事件，並看到更新訊息佇列不為空，因此處理訊息。\n6. 呼叫 `update` 方法，回傳 `true` 表示發生了變化，元件需要重新渲染。\n7. 跳回第 2 步。\n\n您仍然可以在 `rendered` 方法中安排更新，這通常是有用的，但是在這樣做時，請考慮您的元件將如何終止此循環。\n\n## 關聯類型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 類型用於在事件發生後向元件發送訊息；例如，您可能希望在使用者點擊按鈕或向下捲動頁面時執行某些操作。因為元件通常需要回應多個事件，所以 `Message` 類型通常是一個枚舉，其中每個變體都是要處理的事件。\n\n在組織程式碼庫時，將 `Message` 類型的定義包含在定義元件的相同模組中是明智的。您可能會發現採用一致的命名約定來命名訊息類型很有幫助。一個選項（儘管不是唯一的選項）是將類型命名為 `ComponentNameMsg`，例如，如果您的元件名為 `Homepage`，則可以將類型命名為 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示從其父元件傳遞給元件的訊息。此類型必須實作 `Properties` trait（通常透過衍生它）並且可以指定某些屬性是必需的還是可選的。在建立和更新元件時使用此類型。在組件的模組中建立一個名為 `Props` 的結構體，並將其用作組件的 `Properties` 類型是一種常見做法。通常將 \"properties\" 縮寫為 \"props\"。由於 props 是從父元件傳遞下來的，因此應用程式的根元件通常具有 `Properties` 類型為 `()`。如果要為根元件指定屬性，請使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多關於屬性的資訊](./properties)\n:::\n\n## 生命週期上下文\n\n所有組件生命週期方法都接受一個上下文物件。此物件提供了對元件作用域的引用，允許向元件發送訊息並傳遞給元件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Props)'\ndescription: '父子元件通訊'\n---\n\n屬性 (Properties) 使子組件和父組件之間能夠進行通訊。每個元件都有一個關聯的屬性類型，用來描述從父元件傳遞下來的內容。理論上，這可以是任何實現了 `Properties` 特性的類型，但實際上，它應該是一個結構體，其中每個字段代表一個屬性。\n\n## 派生宏\n\n無需自己實作 `Properties` 特性，我們可以用 `#[derive(Properties)]` 來自動生成實作。派生 `Properties` 的型別也必須實作 `PartialEq`。\n\n### 欄位屬性\n\n在派生 `Properties` 時，預設情況下所有欄位都是必要的。以下屬性可讓您為屬性提供初始值，除非它們被設定為另一個值。\n\n:::tip\n屬性不會在 Rustdoc 產生的文件中顯示。您的屬性的文檔字串應該說明一個屬性是否是可選的，以及它是否有一個特殊的預設值。\n:::\n\n#### `#[prop_or_default]`\n\n使用欄位類型的預設值使用 `Default` 特性來初始化屬性值。\n\n#### `#[prop_or(value)]`\n\n使用 `value` 來初始化屬性值。 `value` 可以是傳回欄位類型的任何表達式。例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。\n\n#### `#[prop_or_else(function)]`\n\n呼叫 `function` 來初始化屬性值。 `function` 應該有簽章 `FnMut() -> T`，其中 `T` 是欄位類型。\n\n## `PartialEq`\n\n`Properties` 需要實作 `PartialEq`。這樣，Yew 才能比較它們，以便在它們發生變化時呼叫 `changed` 方法。\n\n## 使用 Properties 的效能開銷\n\n內部屬性是基於引用計數的指標儲存的。這意味著只有一個指標被傳遞到元件樹中的屬性，以避免複製整個屬性所帶來的昂貴效能開銷。\n\n:::tip\n使用 `AttrValue`，這是我們提供的自訂屬性值類型，這樣就可以不用 String 或其他類似的需要克隆的類型。\n:::\n\n## 範例\n\n```rust\nuse yew::Properties;\n/// 從 virtual_dom 中導入 AttrValue\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 鏈接必須有一個目標\n    href: AttrValue,\n    /// 還要注意我們使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 鏈接的顏色，默認為 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值為 None，則視圖函數不會指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當視圖函數沒有指定活動時，默認為 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建立屬性。\n\n這個巨集使用與結構體表達式相同的語法，只是您不能使用屬性或基本表達式 (`Foo { ..base }`)。類型路徑可以直接指向屬性 (`path::to::Props`)，也可以指向元件的關聯屬性 (`MyComp::Properties`)。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 鏈接必須有一個目標\n    href: AttrValue,\n    /// 還要注意我們使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 鏈接的顏色，默認為 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值為 None，則視圖函數不會指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當視圖函數沒有指定活動時，默認為 true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// 注意此函數接收 href 和 text 作為 String\n    /// 我們可以使用 `AttrValue::from` 將其轉換為 `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '引用 (Refs)'\ndescription: '實作越界 DOM 存取'\n---\n\n`ref` 關鍵字可以在任何 HTML 元素或元件中使用，以取得附加到該元素的 DOM `Element`。這可以用於在 `view` 生命週期方法之外對 DOM 進行更改。\n\n這對於獲取 canvas 元素或滾動到頁面的不同部分很有用。例如，在元件的 `rendered` 方法中使用 `NodeRef` 允許您在從 `view` 渲染後對 canvas 元素進行繪製呼叫。\n\n文法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 相關範例\n\n- [節點引用](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: '作用域'\ndescription: '元件的作用域'\n---\n\n## 元件的 `Scope<_>` 接口\n\n`Scope` 是透過訊息建立回呼並更新自己的機制。我們透過在傳遞給元件的上下文物件上呼叫 `link()` 來獲得對它的參考。\n\n### `send_message`\n\n這個函數可以向元件發送訊息。訊息由 `update` 方法處理，該方法決定元件是否應重新渲染。\n\n### `send_message_batch`\n\n這個函數可以同時向元件發送多個訊息。這類似於 `send_message`，但是如果任何訊息導致 `update` 方法傳回 `true`，則元件將在處理批次中的所有訊息後重新渲染。\n\n如果給定的參數向量為空，則此函數不執行任何操作。\n\n### `callback`\n\n建立一個回調，當執行時將向元件發送訊息。在內部，它將使用提供的閉包返回的訊息呼叫 `send_message`。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // 建立一個接受一些文本並將其作為 `Msg::Text` 訊息變體發送到元件的回調。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上一行是多餘的冗長，為了更清晰，可以簡化為這樣：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // 將 `Msg::Text(\"Hello World!\")` 發送到元件。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // 在這裡放置 HTML\n        }\n    }\n}\n```\n\n### `batch_callback`\n\n建立一個回調，執行時將向元件發送一批訊息。與 `callback` 的區別在於，傳遞給此方法的閉包不必傳回訊息。相反，閉包可以傳回 `Vec<Msg>` 或 `Option<Msg>`，其中 `Msg` 是元件的訊息類型。\n\n`Vec<Msg>` 被視為一批訊息，並在內部使用 `send_message_batch`。\n\n`Option<Msg>` 在值為 `Some` 時呼叫 `send_message`。如果值為 `None`，則不執行任何操作。這可以用於根據情況，不需要更新的情況。\n\n這是透過使用僅為這些類型實現的 `SendAsMessage` trait 來實現的。您可以為自己的類型實作 `SendAsMessage`，這樣可以在 `batch_callback` 中使用它們。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/agents.mdx",
    "content": "---\ntitle: '代理 (Agents)'\ndescription: \"Yew's 的代理系統\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n代理程式 (Agents) 是一種將任務卸載到 Web Workers 的方式。\n\n為了使代理程式能夠並發運行，Yew 使用了 [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命週期\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## 代理程式的類型\n\n### 範圍\n\n- 公開 - 在任何給定時間，公共代理的實例最多只有一個。橋樑將在 Web Worker 中產生或連接到已經產生的代理程式。當沒有橋樑連接到此代理時，代理將消失。\n\n- 私有 - 為每個新的橋樑在 Web Worker 中產生一個新的代理程式。這對於將與瀏覽器通訊的共享但獨立的行為從元件中移出是很好的。當連接的橋樑被丟棄時，代理將消失。\n\n- 全域 \\(WIP\\)\n\n## 代理與元件之間的通信\n\n### 通信橋 (Bridges)\n\n通訊橋 (bridge) 是一個元件和代理程式之間的通訊通道。它允許元件向代理發送訊息，並接收來自代理的訊息。\n\n`use_bridge` 鉤子也提供了在函數元件中建立橋樑的功能。\n\n### 派發器 (Dispatchers)\n\n派發器 (Dispatchers) 允許元件和代理程式之間進行單向通信，元件以此方式向代理程式發送訊息。\n\n## 開銷\n\n代理程式使用 Web Workers（即私有和公開）。它們在發送和接收訊息時會產生序列化開銷。代理程式使用 [bincode](https://github.com/bincode-org/bincode) 與其他執行緒通信，因此成本比僅呼叫函數要高得多。\n\n## 進一步閱讀\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 範例展示了元件如何向代理程式傳送訊息並接收來自代理程式的訊息。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: '使用 classes! 巨集處理 CSS 類別'\ndescription: '用一個方便的巨集來處理 CSS 類別'\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew 並沒有提供原生的 CSS-in-Rust 解決方案，但透過提供程式設計方式與 HTML `class` 屬性互動的方式來輔助樣式。\n\n## `classes!` 巨集\n\n`classes!` 巨集和相關的 `Classes` 結構簡化了 HTML 類別的使用：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n更多 CSS 相關的內容請參考[此文檔](../../more/css)。\n\n## 內聯樣式\n\n目前 Yew 並沒有提供特殊的輔助工具來處理透過 `style` 屬性指定的內聯樣式，但你可以像處理其他 HTML 屬性一樣處理它：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n更多 CSS 相關的內容請參考[此文檔](../../more/css)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: '使用 html! 巨集處理 HTML'\ndescription: '這是 HTML，但不完全是！ '\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n你可以使用 `html!` 巨集來寫類似 HTML 的表達式。 Yew 會在背景轉換為表達 DOM 的 Rust 程式碼。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\n類似於格式化表達式，您可以透過使用花括號將周圍上下文的值嵌入 HTML 中：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n使用 `html!` 有一個重要的規則 - 您只能傳回一個包裝節點。為了渲染多個元素的列表，`html!` 允許使用空標籤（Fragments）。空標籤是沒有名稱的標籤，它們本身不會產生 HTML 元素。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// 錯誤：只允許一個根 HTML 元素\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修正：使用 HTML 空標籤包裹\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n更多關於 Yew 和 HTML 的內容請參考[更多 HTML](concepts/html/introduction.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'Javascript 與 Rust'\ndescription: '在 Rust 中使用 JavaScript'\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew 在一個地方集中了一個可重用的 UI 部分可能需要的所有內容 - rust 文件，同時也在必要時保持底層技術的可訪問性。\n\n截至今天，WebAssembly 對於 DOM 互動還不完全支援。這意味著即使在 Yew 中，我們有時也依賴呼叫 JavaScript。接下來是涉及的庫的概述。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一個在 JavaScript 和 Rust 函數之間建立呼叫橋樑的函式庫和工具。\n\n我們強烈建議您查看他們的[文件](https://wasm-bindgen.github.io/wasm-bindgen/)和我們的[快速指南](./wasm-bindgen.mdx)。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 為 Web API 提供了綁定，並允許我們以一種經過 Rust 處理和安全的方式編寫 JavaScript 程式碼。\n\n範例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n再次強調，我們強烈建議您查看他們的[文件](https://wasm-bindgen.github.io/wasm-bindgen/)和我們的[快速指南](./web-sys.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一個在 JavaScript 和 Rust 函數之間建立呼叫橋樑的函式庫和工具。它是由 [Rust 和 WebAssembly 工作小組](https://rustwasm.github.io/) 使用 Rust 建構的。\n\nYew 使用 `wasm-bindgen` 透過一些 crate 與瀏覽器進行互動：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\n本節將從更抽象的層次探討這些 crate，以便更容易理解和使用 Yew 中的 `wasm-bindgen` API。要了解有關 `wasm-bindgen` 及其相關 crate 的更深入指南，請查看 [`wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/)。\n\n有關上述 crate 的文檔，請查看 [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html)。\n\n:::tip\n使用 `wasm-bindgen` doc.rs 搜尋來尋找已使用 `wasm-bindgen` 匯入的瀏覽器 API 和 JavaScript 類型。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\n這個 crate 為上面的其他 crate 提供了許多構建塊。在本節中，我們只會涵蓋 `wasm-bindgen` crate 的兩個主要領域，即巨集和一些您會一遍又一遍看到的類型/特性。\n\n### `#[wasm_bindgen]` macro\n\n`#[wasm_bindgen]` 巨集提供了 Rust 和 JavaScript 之間的接口，提供了一個在兩者之間進行轉換的系統。使用這個巨集更為高級，除非您要使用外部 JavaScript 函式庫，否則不應該使用它。 `js-sys` 和 `web-sys` crate 為內建 JavaScript 類型和瀏覽器 API 提供了 `wasm-bindgen` 定義。\n\n讓我們透過一個簡單的範例來使用`#[wasm-bindgen]` 巨集來匯入一些特定版本的[`console.log`](https://developer.mozilla.org/en-US/docs/Web/ API/Console/log) 函數。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// 首先讓我們手動綁定 `console.log`，而不使用 `web_sys` 的幫助。\n// 在這裡，我們手動寫 `#[wasm_bindgen]` 註解，我們程式的正確性取決於這些註解的正確性！\n#[wasm_bindgen]\nextern \"C\" {\n    // 在這裡使用 `js_namespace` 來綁定 `console.log(..)` 而不是只有 `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` 是多態的，所以我們可以使用多個簽章綁定它。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 多個參數也是可以的！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// 使用導入的函數！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_這個範例是基於 [1.2 使用 console.log 的 `wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) 改編的。 _\n\n### 模擬繼承\n\n在 JavaScript 類別之間的繼承是 JavaScript 語言的核心特性，DOM（文件物件模型）是圍繞它設計的。當使用 `wasm-bindgen` 匯入類型時，您也可以新增描述它們繼承關係的屬性。\n\n在Rust 中，這種繼承關係使用[`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) 和[`AsRef`](https://doc. rust-lang.org/std/convert/trait.AsRef.html) 特性來表示。這裡舉個例子可能會有所幫助；假設您有三種類型 `A`、`B` 和 `C`，其中 `C` 擴展了 `B`，而 `B` 又擴展了 `A`。\n\n在匯入這些類型時，`#[wasm-bindgen]` 巨集將按照下列方式實作 `Deref` 和 `AsRef` 特性：\n\n- `C` 可以 `Deref` 到 `B`\n- `B` 可以 `Deref` 到 `A`\n- `C` 可以被 `AsRef` 到 `B`\n- `C` 和 `B` 都可以被 `AsRef` 到 `A`\n\n這些實作允許您在 `C` 的實例上呼叫 `A` 的方法，並將 `C` 用作 `&B` 或 `&A`。\n\n需要注意的是，使用`#[wasm-bindgen]` 導入的每種類型都有相同的根類型，您可以將其視為上面範例中的`A`，這種類型是[`JsValue`](#jsvalue)，下面有它的部分。\n\n_[`wasm-bindgen` 指引中的 extends 部分](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\n這是 JavaScript 擁有的物件的表示，這是 `wasm-bindgen` 的根捕獲類型。任何來自`wasm-bindgen` 的型別都是`JsValue`，這是因為JavaScript 沒有強型別系統，因此接受變數`x` 的任何函數都不定義其型別，因此`x` 可以是有效的JavaScript 值；因此`JsValue`。如果您正在使用接受 `JsValue` 的導入函數或類型，那麼任何導入的值在技術上都是有效的。\n\n`JsValue` 可以被函數接受，但該函數可能仍然只接受某些類型，這可能會導致panic - 因此在使用原始`wasm-bindgen` API 時，請檢查導入的JavaScript 的文檔，以確定是否會在該值不是某種類型時引發異常（panic）。\n\n_[`JsValue` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)。 _\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust 有一個強型別系統，而 JavaScript…沒有😞。為了讓 Rust 保持這些強型別但仍然方便，WebAssembly 工作小組提出了一個非常巧妙的特性 `JsCast`。它的工作是幫助您從一個JavaScript \"類型\" 轉換到另一個\"類型\"，這聽起來很模糊，但它意味著如果您有一個類型，您知道它是另一個類型，那麼您可以使用`JsCast ` 的函數從一個型別跳到另一個型別。當使用 `web-sys`、`wasm_bindgen`、`js-sys` 時，了解這個很好的特性 - 您會注意到許多類型將從這些 crate 中實作 `JsCast`。\n\n`JsCast` 提供了轉換的檢查和不檢查方法- 因此在運行時，如果您不確定某個物件是什麼類型，您可以嘗試將其轉換，這將返回可能的失敗類型，如[`Option`] (https://doc.rust-lang.org/std/option/enum.Option.html) 和[`Result`](https://doc.rust-lang.org/std/result/enum.Result. html)。\n\n一個常見的例子是在 [`web-sys`](./web-sys.mdx) 中，當您嘗試取得事件的目標時。您可能知道目標元素是什麼，但[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API 總是會回傳一個[` Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)。\n您需要將其轉換為元素類型，以便呼叫其方法。\n\n```rust\n// 需要先導入這個 Trait\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // 也許目標是一個選擇元素？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 做點別的\n        return;\n    }\n\n    // 如果它能確定不是一個選擇元素，那麼我可以肯定它是一個輸入元素！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) 方法是一個檢查的轉換，回傳一個`Option<&T>`，這表示如果轉換失敗，則可以再次使用原始類型，因此傳回`None`。 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 方法將消耗`self`，這是Rust 中`into` 方法的約定，傳回的類型是`Result<T, Self>`。如果轉換失敗，則原始的 `Self` 值將在 `Err` 中傳回。您可以再試一次或對原始類型進行其他操作。\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 類型提供了一種將 Rust 閉包傳遞到 JavaScript 的方法，出於健全性原因，傳遞給 JavaScript 的閉包必須具有 `'static` 生命週期。\n\n這種類型是一個“句柄”，這意味著每當它被丟棄時，它將使其引用的 JS 閉包無效。在 `Closure` 被丟棄後，對 JS 中閉包的任何使用都會引發異常。\n\n當您使用接受型別[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 的`js-sys` 或`web-sys` API 時，通常會使用`Closure`。在[Events](../html/events.mdx) 頁面的[Using `Closure` 部分](../html/events.mdx#using-closure-verbose) 中可以找到Yew 中使用`Closure` 的範例。\n\n_[`Closure` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` crate 提供了 JavaScript 標準內建物件的綁定/導入，包括它們的方法和屬性。\n\n這不包括任何 Web API，因為這是 [`web-sys`](./web-sys.mdx) 的作用！\n\n_[`js-sys` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` crate 提供了一個橋樑，用於將JavaScript Promise 類型作為Rust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 進行處理，並包含將Rust Future 轉換為JavaScript Promise 的實用程式。當在 Rust（wasm）中處理非同步或其他阻塞工作時，這可能很有用，並提供了與 JavaScript 事件和 JavaScript I/O 原語互動的能力。\n\n目前這個 crate 中有三個主要介面：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   一個使用[`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) 建構的類型，然後可以用作`Future<Output=Result<JsValue, JsValue >>`。如果 `Promise` 被解析，這個 `Future` 將解析為 `Ok`，如果 `Promise` 被拒絕，則解析為 `Err`，分別包含 `Promise` 的解析或拒絕值。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   將 Rust `Future<Output=Result<JsValue, JsValue>>` 轉換為 JavaScript `Promise`。未來的結果將轉換為 JavaScript 中的已解析或已拒絕 `Promise`。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   在目前執行緒上產生一個 `Future<Output = ()>`。這是在 Rust 中運行 Future 的最佳方法，而不是將其發送到 JavaScript。\n\n_[`wasm-bindgen-futures` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` 將是 Yew 中 `wasm-bindgen-futures` crate 中最常用的部分，因為這有助於使用具有非同步 API 的函式庫。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // 列印 \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew 還在某些 API 中添加了對 futures 的支持，最值得注意的是您可以創建一個接受 `async` 區塊的 `callback_future` - 這在內部使用了 `spawn_local`。\n\n_[`spawn_local` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys crate 為 Web API 提供綁定。 '\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 為 Web API 提供綁定。這是從瀏覽器 WebIDL 產生的，這就是為什麼有些名稱如此之長，有些類型如此模糊的原因。\n\n## `web-sys` 中的特性 (features)\n\n`web-sys` crate 中啟用了所有特性可能會為 Wasm 應用程式增加很多冗餘。為了解決這個問題，大多數類型都是透過啟用 features 進行控制的，這樣你只需要包含你的應用程式所需的類型。 Yew 啟用了 `web-sys` 的幾個特性，並在其公共 API 中公開了一些類型。你通常需要自行將 `web-sys` 新增為依賴項。\n\n## `web-sys` 中的繼承\n\n在[模擬繼承](./wasm-bindgen.mdx#simulating-inheritance)部分，你可以了解到 Rust 通常提供了一種模擬 JavaScript 中繼承的方法。這在 `web-sys` 中非常重要，因為了解一個類型上有哪些方法意味著了解它的繼承。\n\n這一部分將查看一個特定的元素，並使用Rust 呼叫[`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) 列出其繼承，直到該值為[`JsValue`](./wasm-bindgen.mdx#jsvalue)。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement 是 HTML 中的 <textarea>。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意我們現在已經從 web-sys 類型轉移到內建的 JavaScript 類型，\n    // 這些類型在 js-sys crate 中。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意我們現在已經從 js-sys 類型轉移到 wasm-bindgen crate 中的根 JsValue。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // 這樣使用 deref 意味著我們必須手動遍歷繼承樹。\n    // 但是，您可以在 HtmlTextAreaElement 類型上呼叫 JsValue 方法。\n    assert!(!text_area.is_string());\n\n    // 這個空函數只是為了證明我們可以將 HtmlTextAreaElement 作為 &EventTarget 傳遞。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // 編譯器將沿著 deref 鏈向下走，以符合這裡的類型。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 實作可讓您將 HtmlTextAreaElement 視為 &EventTarget。\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[`wasm-bindgen` 指引中的 `web-sys` 繼承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)_\n\n## `NodeRef` 中的 `Node`\n\nYew 使用 [`NodeRef`](concepts/function-components/node-refs.mdx) 來提供一種方式來保留由 [`html!`](concepts/html/introduction.mdx) 巨集所建立的 `Node` 的引用。 `NodeRef` 中的 `Node` 指的是 [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html)。 `NodeRef::get` 方法將傳回一個 `Option<Node>` 值，但是，在 Yew 中，大多數情況下，您希望將此值轉換為特定元素，以便使用其特定方法。如果存在，可以使用 [`JsCast`](./wasm-bindgen.mdx#JsCast) 對 `Node` 值進行轉換，但是Yew 提供了 `NodeRef::cast` 方法來執行此轉換，以方便使用，因此您不一定需要為 `JsCast` 特性包含 `wasm-bindgen` 依賴項。\n\n下面的兩個程式碼區塊本質上是相同的，第一個使用 `NodeRef::cast`，第二個使用 [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 在 `NodeRef::get` 傳回的 `web_sys::Node` 上。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // 在這裡處理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // 在這裡處理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript 重構為 Rust 的範例\n\n這一節展示如何將與 Web API 互動的 JavaScript 程式碼範例重寫為 Rust 中的 `web-sys`。\n\n### JavaScript 範例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e 為滑鼠事件對象\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 元素内的 x 位置。\n    var y = e.clientY - rect.top // 元素内的 y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### 用 `web-sys` 重寫的範例\n\n只使用 `web-sys`，上面的 JavaScript 範例可以這樣實作：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 需要啟用所有我們想要使用的 web-sys 功能！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 我們現在需要保存 `mousemove` 閉包，以便在事件觸發時閉包仍然在記憶體中。\n```\n\n這個版本更加冗長，但你可能會注意到其中的一部分是由於失敗類型提醒我們，一些函數呼叫有必須保持的不變量，否則將在 Rust 中引發 panic。另一個冗長的部分是呼叫 `JsCast` 來將不同類型轉換為特定類型，以便呼叫其特定方法。\n\n### 用 Yew 重寫的範例\n\n在Yew 中，您將主要建立 [`Callback`](concepts/function-components/callbacks.mdx) 以在 [`html!`](concepts/html/introduction.mdx) 巨集中使用，因此範例將使用這種方法，而不是完全複製上面的方法：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# 我們需要啟用 `DomRect` 特性以使用 `get_bounding_client_rect` 方法。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 補充依賴庫\n\n`web-sys` 是 Web API 的原始綁定，囙此在 Rust 中會有一些痛苦，因為它並不是為 Rust 或甚至强類型系統設計的，這就是社區 crate 提供了對 `web-sys` 的抽象，以提供更符合 Rust 習慣的 API。\n\n_[補充依賴庫清單]（/community/external-libs）_\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/contexts.mdx",
    "content": "---\ntitle: '上下文 (Contexts)'\nsidebar_label: Contexts\ndescription: '使用上下文傳遞深度嵌套資料'\n---\n\n通常，資料是透過 props 從父元件傳遞到子元件。\n但是，如果必須透過中間的許多元件傳遞它們，或者如果應用程式中的許多元件需要相同的訊息，傳遞 props 可能會變得冗長和煩人。\n上下文解決了這個問題，允許父元件使資料可用於其下方樹中的任何元件，無論多深，而無需透過 props 傳遞它們。\n\n## 使用 props 的問題：\"Prop Drilling\"\n\n傳遞 [props](./function-components/properties.mdx) 是從父元件直接傳遞資料到子元件的好方法。\n但是，當需要透過深層嵌套的組件樹傳遞資料或多個組件共享相同的資料時，傳遞 props 變得繁瑣。\n一種常見的資料共享解決方案是將資料提升到一個共同的祖先，並使子元件將其作為 props 接收。\n然而，這可能導致 props 必須通過多個元件才能到達需要它的元件。\n這種情況稱為 \"Prop Drilling\"。\n\n考慮以下範例，它透過 props 傳遞主題：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App 根節點\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n我們透過 `Navbar` 傳遞主題設定，以便它可以到達 `Title` 和 `NavButton`。\n如果 `Title` 和 `NavButton` 這些需要存取主題的元件可以直接存取主題而不必透過 prop 傳遞，那就更好了。\n上下文解決了這個問題，允許父元件將資料（在這種情況下是主題）傳遞給其子元件。\n\n## 使用上下文\n\n### 步驟 1：提供上下文\n\n需要一個上下文提供者來消費上下文。 `ContextProvider<T>`，其中 `T` 是用作提供者的上下文結構體。\n`T` 必須實作 `Clone` 和 `PartialEq`。 `ContextProvider` 是其子元件將擁有上下文的元件。\n當上下文變更時，子元件會重新渲染。一個結構體用來定義要傳遞的資料。 `ContextProvider` 可以這樣使用：\n\n```rust\nuse yew::prelude::*;\n\n/// App 主題\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// 主組件\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` 是 `Rc<UseStateHandle<Theme>>` 類型，而我們需要 `Theme`\n        // 所以我們對它進行解引用。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // 這裡的每個子元件及其子元件都將存取此上下文。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// 工具栏\n/// 此组件可以访问上下文。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// 放置在 `Toolbar` 中的按鈕\n/// 由於此元件是元件樹中 `ThemeContextProvider` 的子元件，它也可以存取上下文。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### 步驟 2：使用上下文\n\n#### 函數元件\n\n`use_context` 鉤子用於在函數元件中使用上下文。\n請參閱 [use_context 文件](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) 以了解更多資訊。\n\n#### 結構體組件\n\n我們有兩種選擇在結構體組件中使用上下文：\n\n- [高階元件](../advanced-topics/struct-components/hoc)：高階函數元件將使用上下文並將資料傳遞給需要它的結構體元件。\n- 直接在結構體組件中使用上下文。請參閱 [結構體組件作​​為消費者的範例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## 使用場景\n\n通常，如果某些資料需要在樹的不同部分的遠端元件中使用，上下文可能會對你有所幫助。\n以下是一些這樣的例子：\n\n- **主題**：你可以在應用程式的頂部放置一個上下文來保存你的應用程式主題，並使用它來調整視覺外觀，如上例所示。\n- **目前使用者帳戶**：在許多情況下，元件需要知道目前登入的使用者。你可以使用上下文將目前使用者物件提供給元件。\n\n### 使用上下文前的考慮\n\n上下文非常容易使用，這也使得它們非常容易被誤用/過度使用。\n僅僅因為你可以使用上下文將 props 共享給多個層級深的元件，並不意味著你應該這樣做。\n\n例如，你可以提取一個元件並將該元件作為子元件傳遞給另一個元件。例如，\n你可能有一個 `Layout` 元件，它將 `articles` 作為 prop 並傳遞給 `ArticleList` 元件。\n你應該重構 `Layout` 元件，使其接受子元件作為 props 並顯示 `<Layout> <ArticleList {articles} /> </Layout>`。\n\n## 修改子元件的上下文值\n\n由於 Rust 的所有權規則，上下文不能有一個可以被子元件呼叫的 `&mut self` 方法。\n要修改上下文的值，我們必須將其與 reducer 結合使用。這可以透過使用\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) 鉤子完成。\n\n[上下文範例](https://github.com/yewstack/yew/tree/master/examples/contexts) 示範了使用上下文的可變上下文\n\n## 進一步閱讀\n\n- [上下文範例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: '回调 (Callbacks)'\n---\n\n回調函數用於在元件樹中向上傳遞訊息，以及在事件處理期間與其他元件（如代理或 DOM）進行通訊。在內部，回調函數的類型只是一個 `Fn`，並且被包裝在 `Rc` 中，以便它們可以被廉價地複製。\n\n如果您想手動呼叫回調函數，可以使用 `emit` 函數。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // 呼叫回調函數\n// web_sys::console::log_1(&result.into()); // 若取消註釋，將列印 \"Bye Bob\"\n```\n\n## 將回呼函數當作屬性傳遞\n\n在 yew 中的一個常見模式是建立一個回呼函數，並將其作為屬性傳遞給子元件。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 然後提供屬性 (Props)\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // 如果取消註釋，這裡會列印文本\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM 事件和回呼函數\n\n回調函數也用於連接到 DOM 事件。\n\n例如，這裡我們定義了一個回呼函數，當使用者點擊按鈕時將會呼叫：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // 如果取消註釋，這裡會列印文本\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子元素 (Children)'\n---\n\n`Children` 是一種特殊的屬性類型，可讓您接收嵌套的 `Html`，就像 html 子元素一樣提供。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` 鍵很重要！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // 可以靠這種方式轉送子元素\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/communication.mdx",
    "content": "---\ntitle: '組件之間的通訊'\n---\n\n## 父元件向子元件發送訊息\n\n將資料作為 [props](./properties) 傳遞，這會導致重新渲染，這是向子元件傳遞訊息的方法。\n\n## 子元件向父元件發送訊息\n\n透過 props 傳遞一個回調，子元件在事件上可以呼叫。 [範例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/generics.mdx",
    "content": "---\ntitle: '泛型元件'\ndescription: '函數元件的 #[component] 屬性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 屬性也適用於用於建立泛型元件的泛型函數。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// 之後可以這樣使用\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// 或者\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: '自訂 Hooks'\n---\n\n## 定義自訂 Hooks\n\n元件的有狀態邏輯可以透過建立自訂 Hooks 來提取為可重複使用的函數。\n\n假設我們希望建立一個事件監聽器，監聽 `window` 物件上的事件。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\n這段程式碼有一個問題：邏輯無法被另一個元件重複使用。如果我們建立另一個監聽不同事件的元件，而不是複製程式碼，我們可以將邏輯移入自訂 hook。\n\n我們將首先建立一個名為 `use_event` 的新函數。 `use_` 前綴表示函數是一個 hook。此函數將接受一個事件目標、一個事件類型和一個回呼。所有 hook 必須在其函數定義上標記為 `#[hook]`。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\n這個簡單的 hook 可以透過組合內建 hook 來創建。在本例中，我們將使用 `use_effect_with` hook，因此當 hook 參數變更時，可以重新建立事件監聽器。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\n儘管這種方法在幾乎所有情況下都有效，但它無法用於編寫像我們已經使用的預定義 hook 那樣的基本 hook。\n\n查看 [docs.rs](https://docs.rs/yew) 上的文件以及 `hooks` 目錄，查看預先定義 hook 的實作。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks 是一類能夠儲存狀態和執行副作用的函數。\n\nYew 提供了一些預先定義的 hooks。您也可以創建自己的 hooks，或發現許多[社區製作的 hooks](/community/awesome#hooks)。\n\n## Hooks 規則\n\n1. 每個 Hook 函數的名稱必須以 `use_` 開頭\n2. Hooks 只能在下列位置使用：\n\n- 函數/ Hook 的頂層\n- 函數/ Hook 內的區塊，只要它沒有被分支\n- 函數/ Hook 內頂層 `if` 表達式的條件\n- 函數/ Hook 內頂層 `match` 表達式的選擇器\n\n3. 每次渲染時，Hooks 必須以相同的順序呼叫。只有在使用 [Suspense](../../suspense.mdx) 時才允許提前返回\n\n這些規則由編譯時或執行時錯誤來執行。\n\n### 預定義 Hooks\n\nYew 提供了以下預定義 Hooks：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\n這些 hooks 的文檔可以在 [Yew API 文件](https://yew-rs-api.web.app/next/yew/functional/)中找到。\n\n### 自訂 Hooks\n\n有些情況下，您可能想要定義自己的 Hooks，以將元件中的可能具有狀態的邏輯封裝到可重複使用的函數中。\n\n## 進一步閱讀\n\n- React 文件中有一個關於 [React hooks](https://reactjs.org/docs/hooks-intro.html) 的部分。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函數組件'\nslug: /concepts/function-components\n---\n\n讓我們重新回顧一下之前的標語：\n\n> Yew 的核心思想是將可重複使用的 UI 部分所需的所有內容集中在一個地方 - Rust 檔案中。\n\n我們將透過引入將定義應用程式的邏輯和呈現行為的概念來完善這個陳述：\"元件\"。\n\n## 什麼是元件？\n\n組件是 Yew 的構建塊。\n\n它們應當：\n\n- 以 [Props](./properties.mdx) 的形式接受參數\n- 可以擁有自己的狀態\n- 計算使用者可見的 HTML 片段（DOM）\n\n## Yew 組件的兩種風味\n\n您目前正在閱讀有關函數元件的內容 - 這是在開始使用 Yew 時以及在編寫簡單的呈現邏輯時編寫元件的建議方式。\n\n還有一種更高級但不太容易訪問的編寫組件的方式 - [結構組件](advanced-topics/struct-components/introduction.mdx)。它們允許非常詳細的控制，儘管大多數情況下您不需要那麼詳細的控制。\n\n## 建立函數元件\n\n若要建立函數元件，請將 `#[component]` 屬性加入到一個函式中。依照慣例，函數的名稱採用 PascalCase，與 `html!` 巨集中的普通 html 元素形成對比。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 然後在其他地方，您可以在 `html!` 中使用元件\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## 組件內部發生了什麼\n\n在渲染時，Yew 將建立這些元件的虛擬樹。它將調用每個（函數）元件的 view 函數來計算 DOM 的虛擬版本（VDOM），您作為庫用戶將其視為 `Html` 類型。對於上面的範例，這將如下所示：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n當需要更新時，Yew 將再次呼叫 view 函數，並將新的虛擬 DOM 與其先前的版本進行協調，並僅將新的/更改的/必要的部分傳 播到實際的 DOM。這就是我們所說的 **渲染**。\n\n:::note\n\n實際上，`Html` 只是 `VNode` 的別名 - 一個虛擬節點。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: '節點引用'\ndescription: 'DOM 外部存取'\n---\n\n`ref` 屬性可以用於將 `NodeRef` 附加到 HTML 元素上。在回呼中，您可以取得 `ref` 附加到的 DOM `Element`。這可以用於在 `view` 生命週期方法之外對 DOM 進行更改，檢索 `<input>` 的值以及透過 javascript API 直接與 DOM 互動。\n\n這對於獲取 canvas 元素或滾動到頁面的不同部分很有用。\n\n:::caution\n不要手動修改 Yew 渲染的 DOM 樹。如果不確定，請將 `NodeRef` 視為唯讀存取。\n:::\n\n## 進一步閱讀\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` 範例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Properties)'\ndescription: '父子元件通訊'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n屬性 (Properties) 通常被簡寫為 \"Props\"。\n\n:::\n\n屬性 (Properties) 是元件的參數，Yew 可以監視這些參數。\n\n在元件的屬性中使用一個類型之前，它必須實作 `Properties` trait。\n\n## 響應性\n\n在重新渲染時，Yew 在協調虛擬 DOM 時檢查屬性是否已更改，以了解是否需要重新渲染巢狀元件。這樣，Yew 可以被認為是一個非常具有響應性的框架，因為來自父組件的變更總是會向下傳播，視圖永遠不會與來自屬性/狀態的資料不同步。\n\n:::tip\n\n如果您尚未完成 [教學](../../tutorial)，請嘗試並自行測試這種回應性！\n\n:::\n\n## 派生宏\n\nYew 提供了一個衍生宏，可以輕鬆地在結構體上實作 `Properties` trait。\n\n您衍生 `Properties` 的型別也必須實作 `PartialEq`，以便 Yew 可以進行資料比較。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函數元件中使用\n\n屬性 `#[component]` 允許在函式參數中選擇性地接收 Props。要提供它們，可以透過 `html!` 巨集中的屬性進行賦值。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// 然後提供屬性\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 沒有屬性需要提供\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生巨集欄位屬性\n\n在派生 `Properties` 時，預設情況下所有欄位都是必要的。\n\n以下屬性可讓您為屬性提供預設值，當父元件沒有設定它們時將使用這些預設值。\n\n:::tip\n屬性在 Rustdoc 產生的文檔中是不可見的。您的屬性的文檔字串應該提到一個屬性是否是可選的，以及它是否有一個特殊的預設值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` trait 的欄位類型的預設值初始化屬性值。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 這樣使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 來初始化屬性值。 `value` 可以是傳回欄位類型的任何表達式。\n\n例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。當屬性被建構時，表達式會被評估，且沒有給出明確的值。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// 這樣使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n呼叫 `function` 來初始化屬性值。 `function` 應該有 `FnMut() -> T` 簽名，其中 `T` 是欄位類型。當沒有為該屬性給出明確的值時，將呼叫該函數。\n這個函數在屬性被建構時被呼叫。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// 使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的效能開銷\n\n內部屬性是以引用計數的智慧型指標傳遞的。這意味著只有一個共享指標被傳遞到元件樹中的屬性，這樣就能節約克隆整個屬性的高昂成本。\n\n:::tip\n`AttrValue` 是我們用於屬性值的自訂類型，這樣就不用將它們定義為 String 或其他類似克隆成本高昂的類型了。\n:::\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建立屬性。\n\n這個巨集使用與結構表達式相同的語法，只是您不能使用屬性或基本表達式 (`Foo { ..base }`)。類型路徑可以直接指向屬性 (`path::to::Props`)，也可以指向元件的關聯屬性 (`MyComp::Properties`)。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 注意我們不需要指定 name 屬性\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自動產生屬性 (yew-autoprops)\n\n為了簡化您的開發流程，您也可以使用巨集 `#[autoprops]`（來自 `yew-autoprops` 套件）自動產生 `Properties` 結構體。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] 巨集必須出現在 #[component] 之前，順序很重要\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 結構體 \"GreetingsProps\" 將會自動產生。\n//\n// `is_loading` 將作為值傳遞給元件，而 `message` 和 `name` 將使用引用，因為定義中有一個前導的 `&`。\n```\n\n## 評估順序\n\n屬性依照指定的順序進行評估，如下例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n雖然幾乎任何 Rust 類型都可以作為屬性傳遞，但有一些反模式應該避免。這些包括但不限於：\n\n1. 使用 `String` 類型而不是 `AttrValue`。 <br />\n   **為什麼不好？ ** `String` 克隆成本高。當屬性值與鉤子和回調一起使用時，通常需要克隆。 `AttrValue` 是一個引用計數的字串 (`Rc<str>`) 或一個 `&'static str`，因此非常便宜克隆。 <br />\n   **注意**：`AttrValue` 在內部是來自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看該包以了解更多資訊。\n2. 使用內部可變性。 <br />\n   **為什麼不好？ ** 內部可變性（例如 `RefCell`、`Mutex` 等）應該 _通常_ 避免使用。它可能會導致重新渲染問題（Yew 不知道狀態何時發生了變化），因此您可能需要手動強制重新渲染。就像所有事物一樣，它有其用武之地。請謹慎使用。\n3. 使用 `Vec<T>` 型別而不是 `IArray<T>`。 <br />\n   **為什麼不好？ ** `Vec<T>`，就像 `String` 一樣，克隆成本也很高。 `IArray<T>` 是一個引用計數的切片 (`Rc<[T]>`) 或一個 `&'static [T]`，因此非常便宜克隆。 <br />\n   **注意**：`IArray` 可以從 [implicit-clone](https://crates.io/crates/implicit-clone) 匯入。查看該包以了解更多資訊。\n4. 您發覺可能的新內容。您是否遇到了一個希望早點了解清楚的邊緣情況？請隨時建立一個問題或向本文檔提供修復的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一個實驗性包，可讓您根據函數的參數動態建立 Props 結構體。如果屬性結構體永遠不會被重複使用，這可能會很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '純組件'\n---\n\n每個函數元件都是一個[純](https://zh.wikipedia.org/zh-hk/%E7%BA%AF%E5%87%BD%E6%95%B0)函數，它接受一個屬性物件並傳回一個`Html` 物件。純函數是指在給定相同輸入時，總是會傳回相同輸出的函數。\n\n這個例子是一個純組件。對於給定的屬性 `is_loading`，它總是傳回相同的 `Html`，沒有任何副作用。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n如果您有一個內部純元件，它不使用 hooks 和其他元件機制，您通常可以將其編寫為傳回 `Html` 的普通函數，從而避免 Yew 運行元件生命週期相關的一些開銷。使用 [表達式語法](concepts/html/literals-and-expressions.mdx#expressions) 在 `html!` 中渲染它們。\n:::\n\n## 非純組件\n\n您可能想知道，如果元件不使用任何全域變量，那麼它是否可以是不“純”的，因為它只是在每次渲染時調用的固定函數。\n這就是下一個主題 - [hooks](./hooks) 的用武之地。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/function-components/state.mdx",
    "content": "---\ntitle: '狀態'\n---\n\n## 如何儲存狀態的一般視圖\n\n這個表格可以作為一個指南，幫助您決定哪種狀態儲存類型最適合您的用例：\n\n| Hook             | 類型                       | 何時渲染?                        | 作用域                   |\n| ---------------- | -------------------------- | -------------------------------- | ------------------------ |\n| [use_state]      | `T`                        | 被設定一個值                     | 組件內部實例             |\n| [use_state_eq]   | `T: PartialEq`             | 被設定一個不同的值               | 組件內部實例             |\n| [use_reducer]    | `T: Reducible`             | 被呼叫歸納                       | 組件內部實例             |\n| [use_reducer_eq] | `T: Reducible + PartialEq` | 被呼叫歸納，歸納後的值與之前不同 | 組件內部實例             |\n| [use_memo]       | `Deps -> T`                | 依賴項發生變化                   | 組件內部實例             |\n| [use_callback]   | `Deps -> Callback<E>`      | 依賴項發生變化                   | 組件內部實例             |\n| [use_mut_ref]    | `T`                        | -                                | 組件內部實例             |\n| 全域靜態常數     | `T`                        | -                                | 全域，任何位置都可以使用 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/classes.mdx",
    "content": "---\ntitle: '類別'\ndescription: '一個方便的巨集來處理類別'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 類別\n\n`Classes` 結構體可以用來處理 HTML 類別。\n\n將字串推送到集合時，`Classes` 確保每個類別都有一個元素，即使單一字串可能包含多個類別。\n\n`Classes` 也可以透過使用 `Extend`（即 `classes1.extend(classes2)`）或 `push()`（即 `classes1.push(classes2)`）來合併。任何實作 `Into<Classes>` 的類型都可以推送到現有的 `Classes` 上。\n\n`classes!` 是一個方便的巨集，它建立一個單一的 `Classes`。它的輸入接受一個逗號分隔的表達式清單。唯一的要求是每個表達式都實作了 `Into<Classes>`。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 接受類別的元件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/components.mdx",
    "content": "---\ntitle: '組件'\ndescription: '使用元件層次結構建立複雜的佈局'\n---\n\n## 基礎\n\n元件可以在 `html!` 巨集中使用：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // 沒有屬性\n        <MyComponent />\n\n        // 使用屬性\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // 一次提供所有屬性\n        <MyComponentWithProps ..props.clone() />\n\n        // 使用變數中的屬性，並覆寫特定值\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## 嵌套\n\n如果組件在其 `Properties` 中有一個 `children` 字段，它可以接受子組件/元素\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` 巨集允許您使用`..props` 語法傳遞一個基本表達式，而不是單獨指定每個屬性，類似於Rust 的[函數式更新語法](https://doc.rust-lang.org /stable/reference/expressions/struct-expr.html#functional-update-syntax)。\n這個基本表達式必須出現在傳遞任何單獨的 props 之後。\n當傳遞一個帶有 `children` 欄位的基本 props 表達式時，`html!` 巨集中傳遞的子元素將覆蓋已經存在於 props 中的子元素。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子元素將覆蓋 props.children\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 相關範例\n\n- [函數化 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [函數化路由](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '條件渲染'\ndescription: '在 html 中有條件地渲染節點！ '\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If 區塊\n\n要有條件地渲染一些標記，我們將其包裝在 `if` 區塊中：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/elements.mdx",
    "content": "---\ntitle: '元素'\ndescription: '支援 HTML 和 SVG 元素'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM 節點\n\n在 Yew 中手動建立或管理 DOM 節點的原因有很多，例如與可能與受管理元件衝突的 JS 庫整合。\n\n使用 `web-sys`，您可以建立 DOM 元素並將其轉換為 `Node` - 然後可以使用 `VRef` 將其用作 `Html` 值：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // 帶記憶能力的函數，只會執行一次\n    let node = use_memo(\n        (),\n        |_| {\n            // 從文件中建立一個 div 元素\n            let div: Element = document().create_element(\"div\").unwrap();\n            // 新增內容、類別等\n            div.set_inner_html(\"Hello, World!\");\n            // 將 Element 轉換為 Node\n            let node: Node = div.into();\n            // 將該 Node 作為 Html 值傳回\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo 回傳的是 Rc 指針，所以我們需要解引用和克隆\n    (*node).clone()\n}\n\n```\n\n## 動態標籤名\n\n在建立高階元件時，您可能會發現自己處於一個標籤名不是靜態的情況。例如，您可能有一個 `Title` 元件，根據等級屬性可以渲染從 `h1` 到 `h6` 的任何內容。而不是使用一個大的匹配表達式，Yew 允許您動態設定標籤名，使用 `@{name}`，其中 `name` 可以是傳回字串的任何表達式。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 邏輯值屬性\n\n一些內容屬性（例如 checked、hidden、required）被稱為邏輯值屬性。在 Yew 中，邏輯值屬性需要設定為布林值：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\n這與以下的 **HTML** 功能上是等價的：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n將邏輯值屬性設為 false 等效於不使用該屬性；可以使用邏輯表達式的值：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\n這與以下 **HTML** 結果等價：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 類似字串的屬性\n\n除了一些邏輯值屬性，您可能會處理許多類似字串的 HTML 屬性，Yew 有幾種選項可以將類似字串的值傳遞給元件。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\n它們都是有效的，**但**我們鼓勵您更傾向於使用 Yew 的自訂 `AttrValue`，特別是如果您需要複製或將它們作為屬性傳遞給另一個元件。\n\n## HTML 元素的可選屬性\n\n大多數 HTML 屬性可以使用可選值（Some(x) 或 None）。這使我們可以在屬性被標記為可選時省略該屬性。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n如果屬性設為 `None`，則該屬性將不會在 DOM 中設定。\n\n## 相關範例\n\n- [內嵌 HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/events.mdx",
    "content": "---\ntitle: '事件'\n---\n\n## 介紹\n\nYew 與 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate 集成，並使用該 crate 中的事件。下面的[表格](#event-types)列出了在 `html!` 巨集中接受的所有 `web-sys` 事件。\n\n您仍然可以為下表中未列出的事件新增 [`Callback`](../function-components/callbacks.mdx)，請參閱[手動事件監聽器](#manual-event-listener)。\n\n## 事件類型\n\n:::tip\n所有的事件類型都在 `yew::events` 下重新匯出。\n使用 `yew::events` 中的類型比手動將 `web-sys` 作為依賴項包含在您的 crate 中更容易確保版本相容性，\n因為您不會使用與 Yew 指定的版本衝突的版本。\n:::\n\n事件監聽器的名稱是在 `html` 巨集中新增事件 `Callback` 時預期的名稱：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\n事件名稱是監聽器名稱去掉 \"on\" 前綴，因此 `onclick` 事件監聽器監聽 `click` 事件。查看本頁末的[完整事件清單](#available-events)及其類型。\n\n## 事件捕獲 {#event-bubbling}\n\nYew 調度的事件遵循虛擬 DOM 層次結構，向上冒泡到監聽器。目前，僅支援監聽器的冒泡階段。請注意，虛擬 DOM 層次結構通常（但並非總是）與實際 DOM 層次結構相同。在處理[傳送門](../../advanced-topics/portals)和其他更高級技術時，這一區別很重要。對於良好實現的元件，直覺應該是事件從子元件冒泡到父元件。這樣，您在 `html!` 中所寫的層次結構就是事件處理程序觀察到的層次結構。\n\n如果您不想要事件冒泡，可以透過呼叫\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n在啟動應用程式*之前*。這會加快事件處理速度，但某些元件可能會因未收到預期的事件而中斷。請謹慎使用！\n\n## 事件委託\n\n可能會讓人驚訝的是，事件監聽器並不是直接註冊在它們被渲染的元素上。相反，事件是從 Yew 應用的子樹根節點委託的。不過，事件仍然以其原生形式傳遞，並且不會創建任何合成形式。這可能會導致 HTML 監聽器中預期的事件與 Yew 中出現的事件之間的不符。\n\n- [`Event::current_target`] 指向 Yew 子樹根節點，而不是新增監聽器的元素。如果您想存取底層的 `HtmlElement`，請使用 [`NodeRef`](../function-components/node-refs.mdx)。\n- [`Event::event_phase`] 總是 [`Event::CAPTURING_PHASE`]。在內部，事件將表現得像是在冒泡階段，事件傳播將被重播，並且事件會[向上冒泡](#event-bubbling)，即虛擬DOM 中較高的事件監聽器將在較低的事件監聽器之後觸發。目前，Yew 不支援捕獲監聽器。\n\n這也意味著由 Yew 註冊的事件通常會在其他事件監聽器之前觸發。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 具備類型的事件目標\n\n:::caution\n在本節中，**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** 總是指的是事件從其派發的元素。\n\n這**不一定**總是指 `Callback` 所放置的元素。\n:::\n\n在事件 `Callback` 中，您可能想要取得該事件的目標。例如，`change` 事件沒有提供任何訊息，但用於通知某些內容已更改。\n\n在 Yew 中，以正確的類型獲取目標元素可以透過幾種方式完成，我們將在這裡逐一介紹。呼叫事件上的[`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) 傳回一個可選的[ `web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 類型，當您想知道輸入元素的值時，這可能看起來不太有用。\n\n在下面的所有方法中，我們將解決相同的問題，以便清楚地了解方法的不同之處，而不是手邊的問題。\n\n**問題：**\n\n我們在 `<input>` 元素上有一個 `onchange` `Callback`，每次呼叫時，我們希望向元件發送一個[更新](components#update) `Msg`。\n\n我們的 `Msg` 列舉如下：\n\n```rust\npub enum Msg {\n InputValue(String),\n}\n```\n\n### 使用 `JsCast`\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate 有一個有用的trait：[`JsCast`](https://rustwasm.github .io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)，它允許我們在類型之間直接轉換，只要它實現了`JsCast` 就行。我們可以謹慎地轉換，這涉及運行時檢查和處理 `Option` 和 `Result` 的邏輯，或者我們也可以冒險直接強行轉換。\n\n多說無益，看代碼：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# 需要 wasm-bindgen 用於呼叫 JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // 當事件被建立時，目標是未定義的，只有在派發時才會新增目標。\n            let target: Option<EventTarget> = e.target();\n            // 事件可能會冒泡，因此此偵聽器可能會捕獲不是 HtmlInputElement 類型的子元素的事件。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // 你必須了解 target 是 HtmlInputElement，否則呼叫 value 將是未定義行為（UB）。\n        // 在這裡，我們確信這是輸入元素，因此我們可以在不檢查的情況下將其轉換為適當的類型。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` 提供的方法是 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\n和 [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)。\n如你所見，它們允許我們從 `EventTarget` 轉換為 [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html)。\n`dyn_into` 方法是謹慎的，因為它會在運行時檢查類型是否實際為 `HtmlInputElement`，如果不是則返回\n`Err(JsValue)`。 [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n是一個通用類型，將原來的物件回傳給你，以便再次嘗試轉換為別的類型。\n\n這會兒你可能會想，什麼時候可以使用危險版本？在上面的情況下，它是安全的<sup>1</sup>，因為我們將 `Callback` 設定在一個沒有子元素的元素上，所以目標只能是同一個元素。\n\n_<sup>1</sup> 只要牽涉到 JS 領域，就是安全的。 _\n\n### 使用 `TargetCast`\n\n**強烈建議先閱讀 [使用 JsCast](#using-jscast)！ **\n\n:::note\n`TargetCast` 的設計目的是讓新用戶了解 `JsCast` 的行為，但範圍更小，僅涉及事件及其目標。\n\n選用 `TargetCast` 或 `JsCast` 純粹是個人偏好，實際您會發現 `TargetCast` 的實作和 `JsCast` 的功能很相似。\n:::\n\n`TargetCast` trait 是在 `JsCast` 基礎之上建構的，專門用於從事件中取得類型化的事件目標。\n\n`TargetCast` 是 Yew 的一部分，因此無需添加依賴項即可在事件上使用 trait 方法，但它的工作方式與 `JsCast` 非常相似。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // 你必須清楚 target 是 HtmlInputElement，否則呼叫 value 將是未定義行為（UB）。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n如果您已經了解了 `JsCast`，或者了解了這個 trait，您可能會發現 `TargetCast::target_dyn_into` 與 `JsCast::dyn_into` 相似，但專門用於事件的目標。 `TargetCast::target_unchecked_into` 與 `JsCast::unchecked_into` 類似，因此上面關於 `JsCast` 的所有警告都適用於 `TargetCast`。\n\n### 使用 `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) 可以取代查詢給定給 `Callback` 的事件。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n透過 `NodeRef`，你可以忽略事件並使用 `NodeRef::cast` 方法取得一個`Option<HtmlInputElement>` - 這是可選的，因為在設定 `NodeRef` 之前呼叫 `cast`，或者當類型不符時將會回傳 `None`。\n\n你可能會看到，透過使用 `NodeRef`，我們不必將 `String` 傳回狀態，因為我們總是存取 `input_node_ref` - 因此我們可以這樣做：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // 對 value 做點什麼\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\n您選擇哪種方法取決於您的元件和您的偏好，沒有所謂的*推薦*方法。\n\n## 手動事件監聽器\n\n您可能想要監聽 Yew 的 `html` 巨集不支援的事件，請查看[這裡列出的支援的事件](#event-types)。\n\n為了手動為某個元素新增事件監聽器，我們需要藉助 [`NodeRef`](../function-components/node-refs.mdx)，以便在 `use_effect_with` 中使用 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) 和 [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API 新增監聽器。\n\n以下範例將展示如何為虛構的 `custard` 事件新增監聽器。所有不受 yew 支援的事件或自訂事件都可以表示為\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html)。如果您需要存取自訂/不受支援事件的特定方法或字段，可以使用\n[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) 的方法將其轉換為所需的類型。\n\n### 使用 `Closure`（冗長版本）\n\n直接使用 `web-sys` 和 `wasm-bindgen` 的介面可能有點痛苦…所以要有點心理準備（[感謝 `gloo`，有了更簡潔的方法](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 建立您通常會建立的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 對 custard 做點什麼..\n                    });\n\n                    // 從 Box<dyn Fn> 創建一個 Closure - 這必須是 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有關 `Closure` 的更多信息，請參見 [wasm-bindgen 指南](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html)。\n\n### 使用 `gloo`（簡潔版本）\n\n更方便的方法是使用 `gloo`，更具體地說是 [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)，\n它是 `web-sys`、`wasm-bindgen` 的高層抽象實作。\n\n`gloo_events` 提供了 `EventListener` 類型，可以用來建立和儲存事件監聽器。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 建立您通常會建立的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 對 custard 做點什麼..\n                    });\n\n                    // 從 Box<dyn Fn> 創建一個 Closure - 這必須是 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有關 `EventListener` 的更多信息，請參見 [gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html)。\n\n## 可用事件的完整清單 {#available-events}\n\n| 偵聽器名稱                  | `web_sys` 事件類型                                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空標籤 (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 巨集總是需要一個根節點。為了繞過這個限制，您可以使用一個“空標籤”（也稱為“fragments”）。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// 錯誤：只允許一個根 HTML 元素\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: '用於產生 HTML 和 SVG 的過程巨集'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 巨集可讓您聲明性地編寫 HTML 和 SVG 程式碼。它類似於 JSX（一種允許您在 JavaScript 中編寫類似 HTML 的程式碼的擴充）。\n\n**重要提示**\n\n1. `html! {}` 巨集只能接受一個根HTML 節點（您可以透過使用[fragments](./fragments.mdx) 或[iterators](./../html/lists.mdx) 來規避這一點）\n2. 空的 `html! {}` 呼叫是有效的，不會渲染任何內容\n3. 字面量必須永遠用引號引起來並用大括號括起來：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` 巨集會將所有標籤名稱轉換為小寫。若要使用大寫字元（某些SVG 元素所需的字元）請使用[動態標籤名稱](concepts/html/elements.mdx#dynamic-tag-names)：`html! { <@{\"myTag\"}>< /@> }`\n\n:::note\n`html!` 巨集可能會達到編譯器的預設遞歸限制。如果遇到編譯錯誤，請在 crate 根目錄中新增類似 `#![recursion_limit=\"1024\"]` 的屬性以解決問題。\n:::\n\n## 標籤 (Tags) 結構\n\n標籤 (Tags) 是基於 HTML 標籤。元件、元素和清單都基於此標籤語法。\n\n標籤必須或自閉合 `<... />`，或對於每個開始標籤都有一個對應的結束標籤。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 缺少閉合標籤\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 缺少閉合標籤\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n方便起見，通常需要閉合標籤的元素**允許**自閉合。例如，編寫 `html! { <div class=\"placeholder\" /> }` 是有效的。\n:::\n\n建立複雜的巢狀 HTML 和 SVG 佈局還是很容易的：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\n如果您使用 Rust 編譯器的開發者版本編譯 Yew，巨集將警告您可能遇到的一些常見陷阱。當然，您可能需要使用穩定版編譯器（例如，您的組織可能有政策要求這樣做）進行發布構建，但即使您使用的是穩定工具鏈，運行`cargo +nightly check` 也可能會標記一些可以改進HTML 程式碼的方法。\n\n目前，這些 lint 主要與可訪問性相關。如果您有 lint 的想法，請隨時[在此問題中發表意見](https://github.com/yewstack/yew/issues/1334)。\n\n## 指定屬性和屬性\n\n屬性與普通 HTML 中的元素設定方式相同：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n屬性在元素名稱之前用 `~` 指定：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n如果值是一個字面量的話，圍繞值的大括號可以省略。\n\n:::\n\n:::note 什麼是字面量\n\n字面量是 Rust 中所有有效的[字面量表達式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)。請注意，[負數**不是**字面量](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)，因此必須用大括號括起來 `{-6}`。\n\n:::\n\n:::note 元件屬性\n元件屬性以 Rust 物件傳遞，與此處所述的元素參數 (Attributes) / 屬性 (Properties) 不同。\n在[元件屬性](../function-components/properties.mdx)中了解更多。\n:::\n\n### 特殊屬性\n\n有一些特殊屬性不會直接影響 DOM，而是作為 Yew 虛擬 DOM 的指令。目前有兩個這樣的特殊屬性：`ref` 和 `key`。\n\n`ref` 可讓您直接存取和操作底層 DOM 節點。有關更多詳細信息，請參閱 [Refs](../function-components/node-refs.mdx)。\n\n另一方面，`key` 為元素提供了一個唯一標識符，Yew 可以用於最佳化目的。\n\n:::info\n[了解更多相關內容](./html/lists)\n:::\n\n## 條件渲染\n\n可以透過使用 Rust 的條件結構來條件性地渲染標記。目前只支援 `if` 和 `if let`。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n閱讀[條件渲染](./conditional-rendering.mdx)一節以了解更多\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/lists.mdx",
    "content": "---\ntitle: '列表'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 迭代器\n\n從迭代器建立 HTML 有 3 種方法：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` 迴圈\">\n主要方法是使用 for 迴圈，與 Rust 中已有的 for 迴圈相同，但有 2 個關鍵區別：\n1. 與標準 for 迴圈不能傳回任何內容不同，`html!` 中的 for 迴圈會被轉換為節點清單；\n2. 發散運算式，即 `break`、`continue` 在 `html!` 中的 for 迴圈主體內是不允許的。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` 區塊\">\n另一種方法是使用 `for` 關鍵字，這不是原生的 Rust 語法，而是由 HTML 巨集用於輸出顯示迭代器所需的程式碼。\n當迭代器已經計算好，只需要將其傳遞給巨集時，這種方法比第一種更好。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` 方法\">\n\n最後一種方法是在迭代器的最終轉換上呼叫 `collect::<Html>()`，它傳回一個 Yew 可以顯示的清單。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 鍵 (Key) 列表\n\n鍵 (Key) 列表是一個最佳化的列表，其中**所有**子元素都有鍵。\n`key` 是 Yew 提供的一個特殊屬性，它為 HTML 元素或元件提供一個唯一標識符，用於 Yew 內部的最佳化。\n\n:::caution\nKey 只需要在每個清單中是唯一的，與 HTML `id` 的全域唯一性相反。它不應該依賴於列表的順序。\n:::\n\n始終建議為清單新增按鍵 (key)。\n\n可以透過將唯一的 `String`、`str` 或整數傳遞給特殊的 `key` 屬性來新增鍵：\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### 效能優化\n\n我們有一個[帶有鍵 (keys) 的列表範例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)可以讓你測試效能上的改進，這裡有一個簡單的測試流程：\n\n1. 進入[線上示範](https://examples.yew.rs/keyed_list)\n2. 新增 500 個元素\n3. 停用鍵\n4. 反轉列表\n5. 看 \"最後一次渲染花費了 Xms\"（在撰寫本文時，大約為 60ms）\n6. 啟用鍵\n7. 再次反轉列表\n8. 看 \"最後一次渲染花費了 Xms\"（在撰寫本文時，大約為 30ms）\n\n截至撰寫本文時，對於 500 個組件，速度提高了 2 倍。\n\n### 原理解釋\n\n通常，當你迭代時，只需要在每個列表項目上添加一個鍵，資料的順序可能會改變。\n在重新渲染清單時，它用於加速協調過程。\n\n如果沒有鍵，假設你迭代 `[\"bob\", \"sam\", \"rob\"]`，最終得到的 HTML 如下：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n然後在下一次渲染時，如果你的清單更改為 `[\"bob\", \"rob\"]`，Yew 可以刪除 id=\"rob\" 的元素，並將 id=\"sam\" 更新為 id=\"rob\"。\n\n如果你為每個元素添加了一個鍵，初始HTML 將保持不變，但在使用修改後的列表`[\"bob\", \"rob\"]` 進行渲染後，Yew 只會刪除第二個HTML 元素，而其他元素則保持不變，因為它可以使用鍵將它們關聯起來。\n\n如果你遇到了一個從一個元件切換到另一個元件的 bug/\"feature\"，但兩者都有一個 div 作為最高渲染元素。\nYew 在這些情況下會重複使用已渲染的 HTML div 作為最佳化。\n如果你需要該 div 被重新建立而不是被重複使用，那麼你可以添加不同的鍵，它們將不會被重複使用。\n\n## 進一步閱讀\n\n- [TodoMVC 範例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [帶有按鍵 (keys) 的清單範例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [路由範例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: '字面量與表達式'\n---\n\n## 字面量\n\n如果表達式解析為實現了 `Display` 的類型，它們將被轉換為字串並插入到DOM 中作為[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 節點。\n\n:::note\n字串字面量會建立 `Text` 節點，瀏覽器將其視為字串。因此，即使表達式包含 `<script>` 標籤，您也不會遇到 XSS 等安全性問題，除非您將表達式包裝在 `<script>` 區塊中。\n:::\n\n所有顯示文字都必須用 `{}` 區塊括起來，因為文字被視為表達式。這是 Yew 與普通 HTML 語法最大的偏差。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 表達式\n\n您可以使用 `{}` 區塊在 HTML 中插入表達式，只要它們解析為 `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常將這些表達式提取到函數或閉包中以優化可讀性是有意義的：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/router.mdx",
    "content": "---\ntitle: '路由 (Router)'\ndescription: 'Yew 的官方路由庫'\n---\n\n單頁應用程式 (SPA) 中的路由器處理根據 URL 顯示不同的頁面。與點擊連結時請求不同的遠端資源的預設行為不同，路由器會在本機設定 URL 以指向應用程式中的有效路由。然後，路由器偵測到此變更並決定要渲染的內容。\n\nYew 在 `yew-router` crate 中提供了路由器支援。要開始使用它，請將依賴項新增至您的 `Cargo.toml` 檔案中。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n所需的工具均在 `yew_router::prelude` 模組中提供，\n\n## 用法\n\n最開始，你需要定義一個 `Route`。\n\n路由由一個 `enum` 定義，它衍生自 `Routable`。這個枚舉必須實作 `Clone + PartialEq`。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` 與 `<Switch />` 元件配對，後者會找到與瀏覽器目前 URL 相符的路徑變體，並將其傳遞給 `render` 回呼。然後回調決定要渲染的內容。如果沒有路徑匹配，路由器會導航到帶有 `not_found` 屬性的路徑。如果沒有指定路由，則不會渲染任何內容，並且會在控制台中記錄一條訊息，說明沒有符合的路由。\n\nyew-router 的大多數元件，特別是 `<Link />` 和 `<Switch />`，必須是某個 Router 元件（例如 `<BrowserRouter />`）的（深層）子元素。通常在應用程式中只需要一個 Router，通常由最頂層的 `<App />` 元件立即渲染。 Router 註冊了一個上下文，這是 Links 和 Switches 功能所需的。下面提供了一個範例。\n\n:::caution\n在瀏覽器環境中使用 `yew-router` 時，強烈建議使用 `<BrowserRouter />`。您可以在 [API 參考](https://docs.rs/yew-router/) 中找到其他路由器類型。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### 路徑段\n\n路由還可以使用動態和命名通配符段從路由中提取資訊。然後，您可以在 `<Switch />` 內存取貼文的 id，並透過屬性將其轉發到對應的元件。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n您也可以使用普通的 `Post` 變體，而不是 `Post {id: String}`。例如，當 `Post` 與另一個路由器一起渲染時，該欄位可能是多餘的，因為另一個路由器可以匹配並處理路徑。有關詳細信息，請參閱下面的[嵌套路由器](#nested-router)部分。\n:::\n\n請注意，欄位必須實作 `Clone + PartialEq` 作為 `Route` 枚舉的一部分。它們還必須實作 `std::fmt::Display` 和 `std::str::FromStr` 以進行序列化和反序列化。整數、浮點數和字串等原始類型已經滿足這些要求。\n\n當路徑的形式匹配，但反序列化失敗（根據 `FromStr`）。路由器將認為路由不匹配，並嘗試渲染未找到的路由（或者如果未指定未找到的路由，則渲染空白頁面）。\n\n參考以下範例：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// 切換函數會渲染 News 和 id。這裡省略了。\n```\n\n當段超過 255 時，`u8::from_str()` 將失敗並傳回 `ParseIntError`，路由器將認為路由不符。\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\n有關路由語法和如何綁定參數的更多信息，請查看 [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params)。\n\n### 位置 (Location)\n\n路由器透過上下文提供了一個通用的 `Location` 結構，可以用來存取路由資訊。它們可以透過鉤子或 `ctx.link()` 上的便捷函數來檢索。\n\n### 導航\n\n`yew_router` 提供了一些工具來處理導航。\n\n#### 連結\n\n`<Link />` 渲染為`<a>` 元素，`onclick` 事件處理程序將呼叫 [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)，並將目標頁面推送到歷史記錄中並渲染所需的頁面，這正是單頁應用程式所期望的行為。普通錨元素的預設 `onclick` 會重新載入頁面。\n\n`<Link />` 元件也會將其子元素傳遞給 `<a>` 元素。可以將其視為應用程式內路由的 `<a/>` 替代品。不同之處在於你需要提供 `to` 屬性而不是 `href`。範例用法如下：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n結構體變數也可以正常運作：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### 導航接口\n\n導航器 API 為函數元件和結構元件提供。它們使回調能夠更改路由。可以在任一情況下取得 `Navigator` 實例以操作路由。\n\n##### 函數式元件\n\n對於函數元件，當底層導覽器提供者變更時，`use_navigator` 鉤子會重新渲染元件。\n以下是實現一個按鈕的範例，該按鈕在點擊時導航到 `Home` 路由。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\n這裡的範例使用了 `Callback::from`。如果目標路由可以與元件所在的路由相同，或只是為了安全起見，請使用普通的回呼。例如，考慮在每個頁面上都有一個徽標按鈕，點擊該按鈕會返回主頁。在主頁上點擊該按鈕兩次會導致程式碼崩潰，因為第二次點擊會推送一個相同的 Home 路由，並且 `use_navigator` 鉤子不會觸發重新渲染。\n:::\n\n如果您想要取代目前的位置而不是將新位置推到堆疊上，請使用 `navigator.replace()` 而不是 `navigator.push()`。\n\n您可能會注意到 `navigator` 必須移動到回呼中，因此不能再次用於其他回呼。幸運的是，`navigator` 實作了 `Clone`，例如，以下是如何為不同的路由設定多個按鈕：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 結構體組件\n\n對於結構體元件，可以透過 `ctx.link().navigator()` API 取得 `Navigator` 實例。其餘部分與函數組件的情況相同。以下是一個渲染單一按鈕的視圖函數範例。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### 重定向\n\n`yew-router` 在 prelude 中也提供了一個 `<Redirect />` 元件。它可以用於實現與導航器 API 類似的效果。該元件接受一個 `to` 屬性作為目標路由。當渲染 `<Redirect/>` 時，使用者將被重定向到屬性中指定的路由。以下是一個範例：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // 建立對 `use_user` 的鉤子\n    let user = match use_user() {\n        Some(user) => user,\n        // 當使用者為 `None` 時重定向到登入頁面\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 實際頁面內容\n}\n```\n\n:::tip 如何選擇 `Redirect` 或 `Navigator`\nNavigator API 是在回呼中操作路由的唯一方法。\n而 `<Redirect />` 可以作為元件中的回傳值使用。您可能還想在其他非元件上下文中使用 `<Redirect />`，例如在[嵌套路由器](#nested-router)的 switch 函數中。\n:::\n\n### 監聽變化\n\n#### 函數式元件\n\n您可以使用 `use_location` 和 `use_route` 鉤子。當提供的值發生變化時，您的元件將重新渲染。\n\n#### 結構體組件\n\n為了回應路由變化，您可以將回呼閉包傳遞給 `ctx.link()` 的 `add_location_listener()` 方法。\n\n:::note\n一旦位置監聽器被刪除，它將被取消註冊。請確保將句柄儲存在元件狀態中。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // 處理事件\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` 和 `ctx.link().route::<R>()` 也可以用於一次性擷取位置和路由。\n\n### 查詢參數\n\n#### 在導航時指定查詢參數\n\n為了在導覽到新路由時指定查詢參數，可以使用 `navigator.push_with_query` 或 `navigator.replace_with_query` 函數。它使用 `serde` 將參數序列化為 URL 的查詢字串，因此任何實作了 `Serialize` 的類型都可以傳遞。最簡單的形式是包含字串對的 `HashMap`。\n\n#### 取得目前路由的查詢參數\n\n`location.query` 用來取得查詢參數。它使用 `serde` 從 URL 的查詢字串中反序列化參數。\n\n## 嵌套路由器\n\n當應用程式變得更大時，嵌套路由器可能會很有用。考慮以下路由器結構：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\n嵌套的 `SettingsRouter` 處理所有以 `/settings` 開頭的 URL。此外，它會將未符合的 URL 重新導向到主 `NotFound` 路由。因此，`/settings/gibberish` 將會重新導向到 `/404`。\n\n:::caution\n\n請注意，該介面仍在開發中，這樣寫的方式尚未最終確定\n\n:::\n\n可以使用以下程式碼實作：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### 基底路徑 (Basename)\n\n可以使用 `yew-router` 定義基底路徑 (Basename)。\n基底路徑是所有路由的公共前綴。導航器 API 和 `<Switch />` 元件都支援基底路徑設定。所有推送的路由都會加上基底路徑前綴，所有的 switch 都會在嘗試將路徑解析為 `Routable` 之前去掉基底路徑。\n\n如果沒有為 Router 元件提供基底路徑屬性，它將使用 HTML 檔案中 `<base />` 元素的 href 屬性，並在 HTML 檔案中沒有 `<base />` 元素時回退到 `/`。\n\n## 相關範例\n\n- [路由](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## 介面參考\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/concepts/suspense.mdx",
    "content": "---\ntitle: '佔位標籤 (Suspense)'\ndescription: '用於資料獲取的佔位標籤'\n---\n\n佔位標籤 (Suspense) 是一種在等待任務完成前暫停元件渲染的方式，同時顯示一個回退（佔位符）UI。\n\n它可以用於從伺服器取得數據，等待代理完成任務，或執行其他後台非同步任務。\n\n在佔位標籤出現之前，資料擷取通常發生在元件渲染之後（渲染時取得）或之前（取得後渲染）。\n\n### 邊渲染，邊下載\n\n佔位標籤 (Suspense) 提供了一種新的方法，允許元件在渲染過程中啟動資料請求。當元件啟動資料請求時，渲染過程將被暫停，並顯示一個回退 UI，直到請求完成。\n\n建議使用鉤子 (Hook) 來使用佔位標籤。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n在上面的範例中，`use_user` 鉤子將在載入使用者資訊時暫停元件渲染，並在載入 `user` 之前顯示 `Loading...` 佔位符。\n\n要定義一個暫停元件渲染的鉤子，它需要傳回一個 `SuspensionResult<T>`。當元件需要暫停時，鉤子應該傳回一個 `Err(Suspension)`，使用者應該使用 `?` 解包它，這樣它將被轉換為 `Html`。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 當使用者載入完成時，我們將其作為 Ok(user) 傳回。\n        Some(m) => Ok(m),\n        None => {\n            // 當使用者仍在載入時，我們建立一個 `Suspension`\n            // 並在資料載入完成時呼叫 `SuspensionHandle::resume`，\n            // 元件將自動重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### 關於實作暫停鉤子 (Hook) 的注意事項\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) 傳回 2 個值：暫停上下文本身和一個暫停句柄。後者負責在何時重新渲染暫停的元件，它提供了 2 種可互換的方法：\n\n1. 呼叫其 [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) 方法。\n2. 丟棄句柄。\n\n:::danger\n\n暫停句柄必須儲存直到更新元件的時候，也就是使用新接收的資料；否則，暫停的元件將進入無限重新渲染循環，從而影響效能。\n在上面的範例中，暫停句柄會透過移至閉包中並傳遞給 `on_load_user_complete` 來儲存。\n當虛擬使用者載入時，將呼叫閉包，從而呼叫 `handle.resume()` 並重新渲染與暫停上下文相關的元件。\n\n:::\n\n# 完整範例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 如果用戶已加載，則將其作為 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 當使用者仍在載入時，我們建立一個 `Suspension`\n            // 並在資料載入完成時呼叫 `SuspensionHandle::resume`，\n            // 元件將自動重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 在結構體組件中使用佔位標籤\n\n直接暫停結構體組件是不可能的。然而，您可以使用函數元件作為[高階元件](../advanced-topics/struct-components/hoc)來實現基於佔位標籤的資料取得。\n\nYew 倉庫中的[佔位標籤範例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)示範如何使用這個元件。\n\n## 相關範例\n\n- [佔位標籤](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: '建立一個範例應用'\n---\n\n當您的環境準備好後，您可以選擇使用一個包含基本 Yew 應用所需樣板的起始模板，或手動設定一個小項目。\n\n## 使用模板快速起步\n\n請依照 [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) 的安裝說明安裝工具，然後執行下列指令：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手動設定應用\n\n### 建立項目\n\n首先，請建立一個新的 cargo 專案。\n\n```bash\ncargo new yew-app\n```\n\n開啟新建立的目錄。\n\n```bash\ncd yew-app\n```\n\n### 運行一個 hello world 範例\n\n為了驗證 Rust 環境是否設定正確，使用 `cargo run` 執行初始專案。您應該會看到一個 \"Hello World!\" 訊息。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### 將項目設定為 Yew web 應用\n\n為了將這個簡單的命令列應用程式轉換為一個基本的 Yew web 應用程序，需要進行一些更改。\n\n#### 更新 Cargo.toml\n\n將 `yew` 加入到依賴清單中。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在建立一個應用程序，你只需要 `csr` 特性。它將啟用 `Renderer` 和所有與客戶端渲染相關的程式碼。\n\n如果你正在製作一個函式庫，請不要啟用此特性，因為它會將客戶端渲染邏輯拉入伺服器端渲染包中。\n\n如果你需要 Renderer 進行測試或範例，你應該在 `dev-dependencies` 中啟用它。\n\n:::\n\n#### 更新 main.rs\n\n我們需要產生一個模板，設定一個名為 `App` 的根元件，該元件渲染一個按鈕，當點擊時更新其值。用以下程式碼取代 `src/main.rs` 的內容。\n\n:::note\n`main` 函數中的 `yew::Renderer::<App>::new().render()` 呼叫啟動您的應用程式並將其掛載到頁面的 `<body>` 標籤上。如果您想要使用任何動態屬性啟動您的應用程序，您可以使用 `yew::Renderer::<App>::with_props(..).render()`。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### 建立 index.html\n\n最後，在應用程式的根目錄中新增一個 `index.html` 檔案。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## 查看您的 Web 應用\n\n運行以下命令在本地建置和提供應用程式。\n\n```bash\ntrunk serve\n```\n\n:::info\n新增選項 '--open' 來開啟您的預設瀏覽器 `trunk serve --open`。\n:::\n\nTrunk 將在您修改任何原始程式碼檔案時即時重新建立您的應用程式。\n預設情況下，伺服器將在位址 '127.0.0.1' 的連接埠 '8080' 上監聽 => [http://localhost:8080](http://127.0.0.1:8080)。\n若要變更這部分配置，請建立以下檔案並根據需要進行編輯：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 區域網路上的監聽位址\naddress = \"127.0.0.1\"\n# 廣域網路上的監聽位址\n# address = \"0.0.0.0\"\n# 監聽的端口\nport = 8000\n```\n\n## 恭喜\n\n現在您已經成功設定了您的 Yew 開發環境，並建立了您的第一個 Web 應用程式。\n\n嘗試這個應用程序，並查看[範例](./examples.mdx)以進一步學習。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/getting-started/editor-setup.mdx",
    "content": "---\ntitle: '設定編輯器'\ndescription: '設定您的程式碼編輯器'\n---\n\n:::important 改進文檔\n有在使用不同的編輯器？如有推薦，請隨意新增您選擇的編輯器的說明。\n:::\n\n## 為建立元件新增模板\n\n### JetBrains IDEs\n\n1. 從導覽列依序點擊 File | Settings | Editor | Live Templates.\n2. 選擇 Rust 並點選 + 圖示新增新的 Live Template。\n3. 根據需要給它一個的名稱和描述。\n4. 將以下程式碼片段貼到範本文字部分。\n5. 在右下角更改適用性，選擇 Rust > Item > Module\n\n對於函數式元件，使用以下模板。\n\n- (可選) 點選編輯變量，並給 `tag` 一個合理的預設值，例如 \"div\"，用雙引號。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n對於結構體組件，可以使用以下更複雜的模板。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. 從導覽列依序點選 File > Preferences > User Snippets.\n2. 選擇 Rust 作為設定語言。\n3. 在 JSON 檔案中加入以下程式碼片段：\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## 支援 `html!` 宏\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 擴展\n\n> 這是一個**正在進行中**的，**由社區維護**的項目！ [請查看詳細信息，並將相關的 bug 報告/問題/疑問直接發送到擴展的存儲庫](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 擴充 [可在 VSC Marketplace 上找到](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)，提供語法高亮、重新命名、懸停等功能。\n\nEmmet 支援應該可以直接使用，如果不能，請回退到編輯 `settings.json` 檔案：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> 下面的配置適用於[LazyVim](https://www.lazyvim.org) 配置和lazy.vim 插件，請在`lua/plugins/nvim-lspconfig.lua` 中建立一個檔案（或更新您的` lspconfig`）：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/getting-started/examples.mdx",
    "content": "---\ntitle: '範例'\n---\n\nYew 倉庫包含許多[範例]（維護狀態各異）。\n我們建議瀏覽它們以了解如何使用框架的不同功能。\n我們也歡迎拉取請求和問題，以便在它們不可避免地被忽略並需要一些幫助 ♥️ 時使用。\n\n有關更多詳細信息，包括示例列表，請參閱[README]。\n\n:::note\n大多數範例都有一個可以在 https://examples.yew.rs/< example_name > 找到的線上部署。\n在各自的子資料夾中的 README 頁面上點擊它們的徽章以導航到線上演示。\n:::\n\n[範例清單]: https://github.com/yewstack/yew/tree/master/examples\n[範例文件 README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/getting-started/introduction.mdx",
    "content": "---\ntitle: '開始使用'\n---\n\n你需要一些工具來編譯、建置、打包和調試你的 Yew 應用程式。在最開始，我們建議使用 [Trunk](https://trunkrs.dev/)。 Trunk 是用於 Rust 的 WASM Web 應用程式打包工具。\n\n## 安裝 Rust\n\n要安裝 Rust，請按照[官方說明](https://www.rust-lang.org/tools/install)。\n\n:::important\nYew 支援的最低 Rust 版本（MSRV）是 `1.84.0`。舊版將無法編譯。您可以使用 `rustup show`（在「active toolchain」下）或 `rustc --version` 檢查您的工具鏈版本。若要更新您的工具鏈，請執行 `rustup update`。\n:::\n\n## 安裝 WebAssembly 目標\n\nRust 可以為不同的「目標」（例如不同的處理器）編譯原始碼。用於基於瀏覽器的 WebAssembly 的編譯目標稱為 `wasm32-unknown-unknown`。以下命令將向您的開發環境新增 WebAssembly 目標。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## 安裝 Trunk\n\nTrunk 是建議的管理部署和包裝的工具，並在整個文件和範例中使用。\n\n```shell\n# 需要注意的是，這可能需要一段時間來安裝，因為它會從頭開始編譯所有內容\n# Trunk 也為許多主要的套件管理器提供了預先建置的二進位文件\n# 有關更多詳細信息，請參見 https://trunkrs.dev/#install\ncargo install --locked trunk\n```\n\n### 其他選項\n\n除了 Trunk 之外，還有其他選項可用於打包 Yew 應用程式。您可能想嘗試以下選項之一：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (仍在早期開發階段)\n\n## 下一步\n\n設定好開發環境後，現在可以繼續閱讀文件。如果您喜歡透過動手實作來學習，我們建議您查看我們的[教學](../tutorial)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\n一個關於如何最好地將CSS 支援整合到Yew 中的討論可以在這裡找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n這裡包含了很多關於如何最好地將 CSS 支援整合到 Yew 中的討論。\n\n目前，我們採用的方法是鼓勵開發者在採用最受歡迎的系統之前建立許多系統。\n\n社區目前正在開發幾個項目，以便為項目添加樣式。以下是其中的一些：\n\n#### 元件庫\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - 沒有任何 JavaScript 依賴的 Yew 樣式框架。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design 元件。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS 元件。\n- [Yewtify](https://github.com/yewstack/yewtify) – 在 Yew 中實作 Vuetify 框架所提供的功能。\n\n#### 樣式解決方案\n\n- [stylist](https://github.com/futursolo/stylist-rs) - 用於 WebAssembly 應用程式的 CSS-in-Rust 樣式解決方案。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind 實用類別。\n\n:::important 改進文檔\n如果您正在開發一個為 Yew 添加樣式的項目，請提交一個 PR 將自己添加到這個列表中！\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/more/debugging.mdx",
    "content": "---\ntitle: '調試'\n---\n\n## 意外終止 (Panics)\n\nYew 會自動在瀏覽器控制台中輸出意外終止日誌。\n\n## 控制台日誌\n\n在 JavaScript 中，`console.log()` 用於輸出到瀏覽器控制台。以下是一些 Yew 的選項。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate 與 [`log`](https://crates.io/crates/log) crate 集成，以將日誌等級、來源行和檔案名稱傳送到瀏覽器控制台。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\n這個 crate 是 Gloo 的一部分，提供了對瀏覽器 API 的 Rust 包裝。 `log!` 巨集可以直接接受 `JsValue`，比 `wasm_logger` 更容易使用。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` 可以與 [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) 一起使用，將訊息輸出到瀏覽器控制台。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## 偵錯元件生命週期\n\n[`tracing`](https://crates.io/crates/tracing) 可用於收集與組件生命週期相關的事件資訊。 `tracing` 還附帶一個 `log` 支援的特性標誌，可以與 `wasm-logger` 很好地整合。\n\n[編譯時過濾器](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) 可以用於調整詳細程度或停用日誌記錄，這應該會導致更小的Wasm 檔案。\n\n## 來源映射 (Source Maps)\n\n有一些支援 [來源映射](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf)。但是，需要一些配置。\n\n## 過去的文章\n\n以下是一些關於 Rust 中 WebAssembly 偵錯狀態的過去文章。它們可能是有趣的閱讀。\n\n\\[Dec 2019\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 這些工作還有很多要做。例如，在工具方面，Emscripten（Binaryen）和 wasm-pack（wasm-bindgen）尚未支援在它們執行的轉換上更新 DWARF 資訊。\n\n\\[2020\\] [Rust Wasm 偵錯指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸的是，WebAssembly 的調試能力仍然不成熟。在大多數Unix 系統上，[DWARF](http://dwarfstd.org/) 用於編碼調試器需要提供運行中程序的源級檢查的信息，就連在Windows 上有一種編碼類似信息的替代格式。但目前，WebAssembly 並沒有對應的格式。\n\n\\[2019\\] [Rust Wasm 路線圖](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 偵錯很棘手，因為很多情況不在這個工作小組的掌控之中，而是取決於 WebAssembly 標準化機構和實現瀏覽器開發者工具的人。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/more/deployment.mdx",
    "content": "---\ntitle: '部署'\ndescription: '部署 Yew 應用程式'\n---\n\n當您準備將 Yew 應用程式部署到伺服器時，您有多種部署方案可以選擇。\n\n`trunk build --release` 會以發布模式建立您的應用程式。設定您的HTTP 伺服器，以便在存取您的網站時提供`index.html`，並且對於靜態路徑（例如`index_<hash>.js` 和`index_bg_<hash>.wasm`）的請求，應該從trunk產生的dist 目錄中提供相應的內容。\n\n:::important 有關 `trunk serve --release`\n不要在生產環境中使用 `trunk serve --release` 來提供您的應用程式。\n它只應該用於在開發過程中測試發布版本建置。\n:::\n\n## 伺服器配置\n\n### 將 `index.html` 當作回退提供\n\n如果應用程式使用了 [Yew 路由](concepts/router.mdx)，您必須設定伺服器在請求不存在的檔案時傳回 `index.html`。\n\n具有 Yew 路由的應用程式被建構為 [單頁應用程式 (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA)。當使用者從正在執行的用戶端導覽到 URL 時，路由器會解釋 URL 並路由到該頁面。\n\n但是在刷新頁面或在網址列中輸入 URL 時，這些操作都是由瀏覽器本身處理的，而不是由正在執行的應用程式處理。瀏覽器直接向伺服器請求該 URL，繞過了路由器。錯誤配置的伺服器會回傳 404 - 未找到 狀態。\n\n透過返回 `index.html`，應用程式會像通常一樣加載，就好像請求是 `/`，直到路由器注意到路由是 `/show/42` 並顯示相應的內容。\n\n### 為 Web Assembly 資源配置正確的 MIME 類型。\n\nWASM 檔案必須使用 `application/wasm` MIME 類型設定 [Content-Type 頭](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。\n\n大多數伺服器和託管服務預設已經這樣做。如果您的伺服器沒有這樣做，請查閱其文件。在大多數 Web 瀏覽器中，錯誤的 MIME 類型會導致類似以下的錯誤：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 為相對路徑構建\n\n預設情況下，trunk 會假定您的網站在 `/` 處提供，並相應地建立網站。可以透過在 `index.html` 檔案中加入 `<base data-trunk-public-url />` 來覆寫此行為。 Trunk 會重寫此標籤以包含傳遞給 `--public-url` 的值。 Yew 路由會自動偵測 `<base />` 的存在並適當處理。\n\n## 使用環境變數自訂行為\n\n通常使用環境變數來自訂建構環境。由於應用程式在瀏覽器中運行，我們無法在運行時讀取環境變數。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) 巨集可以在編譯時取得環境變數的值。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/more/roadmap.mdx",
    "content": "---\ntitle: '路線圖'\ndescription: 'Yew 框架的計劃功能路線圖'\n---\n\n## 優先權\n\n框架即將推出的功能和重點的優先順序由社群決定。\n在 2020 年春季，我們發送了一份開發者調查，以收集關於專案方向的回饋。\n您可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到調查摘要。\n\n:::note\n所有主要倡議的狀態都可以在 Yew Github [專案看板](https://github.com/yewstack/yew/projects) 上跟踪\n:::\n\n## 重點\n\n1. 最受歡迎的功能\n2. 生產就緒\n3. 文件\n4. 痛點\n\n### 最受歡迎的功能\n\n1. [函數組件](https://github.com/yewstack/yew/projects/3)\n2. [元件庫](https://github.com/yewstack/yew/projects/4)\n3. 更好的狀態管理\n4. [伺服器端渲染](https://github.com/yewstack/yew/projects/5)\n\n### 生產就緒所需的問題\n\n- 提高 Yew 測試覆蓋率\n- 減少二進位檔案大小\n- [效能基準測試](https://github.com/yewstack/yew/issues/5)\n\n### 文件\n\n- 建立教程\n- 簡化項目設置\n\n### 痛點\n\n- [組件樣板](https://github.com/yewstack/yew/issues/830)\n- [代理](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/more/testing.mdx",
    "content": "---\ntitle: '測試應用'\ndescription: '測試你的應用程式'\n---\n\n:::info\n我們正在努力讓測試組件變得更容易，但目前仍在進行中。\n\n在 GitHub 倉庫中可以找到對 [淺渲染](https://github.com/yewstack/yew/issues/1413) 的支援。\n:::\n\n## 快照測試\n\nYew 提供了 `yew::tests::layout_tests` 模組來方便元件的快照測試。\n\n:::important 改進文檔\n我們需要幫助，以改進快照測試的文件。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM 工作小組維護了一個稱為 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) 的 crate，\n它允許你以類似於內建的 `#[test]` 過程巨集的方式在瀏覽器中執行測試。\n有關此模組的更多信息，請參閱 [Rust Wasm 工作組的文檔](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22/tutorial/index.mdx",
    "content": "---\ntitle: '教學'\nslug: /tutorial\n---\n\n## 介紹\n\n在這個實作教程中，我們將學習如何使用 Yew 建立 Web 應用程式。\n**Yew** 是一個現代的 [Rust](https://www.rust-lang.org/) 框架，用於使用 [WebAssembly](https://webassembly.org/) 建立前端 Web 應用程式。\nYew 透過利用 Rust 強大的類型系統，鼓勵可重複使用、可維護和良好結構化的架構。\n一個龐大的社群所創造的函式庫生態系統，稱為Rust 中的[crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)，為常用模式（如狀態管理）提供了元件。\nRust 的套件管理器 [Cargo](https://doc.rust-lang.org/cargo/) 允許我們利用 [crates.io](https://crates.io) 上提供的大量 crate，例如 Yew。\n\n### 我們將要建構的內容\n\nRustconf 是 Rust 社群每年舉辦的星際派對。\nRustconf 2020 有大量的演講，提供了大量的資訊。\n在這個實作教程中，我們將建立一個 Web 應用程序，幫助其他 Rustaceans 了解這些演講並從一個頁面觀看它們。\n\n## 設定\n\n### 先決條件\n\n這個教程假設您已經熟悉 Rust。如果您是Rust 的新手，免費的[Rust 書](https://doc.rust-lang.org/book/ch00-00-introduction.html) 為初學者提供了一個很好的起點，並且即使對於有經驗的Rust 開發人員來說，它仍然是一個很好的資源。\n\n確保安裝了最新版本的 Rust，方法是執行 `rustup update` 或[安裝 Rust](https://www.rust-lang.org/tools/install)。\n\n安裝 Rust 後，您可以使用 Cargo 執行以下命令安裝 `trunk`：\n\n```bash\ncargo install trunk\n```\n\n我們還需要新增 WASM 建置目標，執行以下命令：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### 設定項目\n\n首先，建立一個新的 cargo 專案：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\n為了驗證 Rust 環境是否設定正確，使用 cargo 建置工具執行初始專案。\n在關於建置過程的輸出之後，您應該會看到預期的 \"Hello, world!\" 訊息。\n\n```bash\ncargo run\n```\n\n## 我們的第一個靜態頁面\n\n為了將這個簡單的命令列應用程式轉換為一個基本的 Yew web 應用程序，需要進行一些更改。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在建立一個應用程序，你只需要 `csr` 特性。它將啟用 `Renderer` 和所有與客戶端渲染相關的程式碼。\n\n如果你正在製作一個函式庫，請不要啟用此特性，因為它會將客戶端渲染邏輯拉入伺服器端渲染包中。\n\n如果你需要 Renderer 進行測試或範例，你應該在 `dev-dependencies` 中啟用它。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n現在，讓我們在專案的根目錄中建立一個 `index.html`。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 啟動開發伺服器\n\n運行以下命令建置並在本地提供應用程式。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n刪除選項 '--open' 以在執行 `trunk serve` 後不開啟預設瀏覽器。\n:::\n\nTrunk 將在您修改任何原始程式碼檔案時即時重新建立您的應用程式。\n預設情況下，伺服器將在位址 '127.0.0.1' 的連接埠 '8080' 上監聽 => [http://localhost:8080](http://127.0.0.1:8080)。\n若要變更這部分配置，請建立以下檔案並根據需要進行編輯：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 區域網路上的監聽位址\naddress = \"127.0.0.1\"\n# 廣域網路上的監聽位址\n# address = \"0.0.0.0\"\n# 監聽的端口\nport = 8000\n```\n\n如果您有興趣，您可以執行 `trunk help` 和 `trunk help <subcommand>` 以獲取更多關於正在進行的流程的詳細資訊。\n\n### 恭喜\n\n您現在已經成功設定了 Yew 開發環境，並建立了您的第一個 Yew Web 應用程式。\n\n## 建立 HTML\n\nYew 利用了 Rust 的過程宏，並為我們提供了一種類似於 JSX（JavaScript 的擴展，可讓您在 JavaScript 中編寫類似 HTML 的程式碼）的語法來建立標記。\n\n### 轉換為經典 HTML\n\n由於我們已經對我們的網站長什麼樣子有了一個很好的想法，我們可以簡單地將我們的草稿轉換為與 `html!` 相容的表示。如果您習慣於編寫簡單的 HTML，那麼您在 `html!` 中編寫標記時應該沒有問題。要注意的是，這個巨集與 HTML 有一些不同之處：\n\n1. 表達式必須用大括號（`{ }`）括起來\n2. 只能有一個根節點。如果您想要在不將它們包裝在容器中的情況下擁有多個元素，可以使用空標籤/片段（`<> ... </>`）\n3. 元素必須正確關閉。\n\n我們想要建立一個佈局，原始 HTML 如下：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\n現在，讓我們將這個 HTML 轉換為 `html!`。將下列程式碼片段輸入（或複製/貼上）到 `app` 函數的主體中，以便函數傳回 `html!` 的值\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\n刷新瀏覽器頁面，您應該看到以下輸出：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### 在標記中使用 Rust 語言結構\n\n在 Rust 中編寫標記的一個很大的優勢是，我們在標記中獲得了 Rust 的所有優點。\n現在，我們不再在 HTML 中硬編碼影片列表，而是將它們定義為 `Vec` 的 `Video` 結構體。\n我們建立一個簡單的 `struct`（在 `main.rs` 或我們選擇的任何檔案中）來保存我們的資料。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n接下來，我們將在 `app` 函數中建立這個結構體的實例，並使用它們來取代硬編碼的資料：\n\n```rust\nuse website_test::tutorial::Video; // 換成你自己的路徑\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\n為了顯示它們，我們需要將 `Vec` 轉換為 `Html`。我們可以透過建立一個迭代器，將其映射到 `html!` 並將其收集為 `Html` 來實現：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\n在清單項目上使用鍵有助於 Yew 追蹤清單中哪些項目發生了變化，從而實現更快的重新渲染。 [始終建議在清單中使用鍵](/concepts/html/lists.mdx#keyed-lists)。\n:::\n\n最後，我們需要用從資料建立的 `Html` 取代硬編碼的影片清單：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## 元件\n\n組件是 Yew 應用程式的構建塊。透過組合組件（可以由其他組件組成），我們建立我們的應用程式。透過為可重複使用性建立元件並保持它們的通用性，我們將能夠在應用程式的多個部分中使用它們，而無需重複程式碼或邏輯。\n\n到目前為止我們一直在使用的 `app` 函數是一個元件，稱為 `App`。它是一個「函數式元件」。\n\n1. 結構體組件\n2. 函數式組件\n\n在本教程中，我們將使用函數式元件。\n\n現在，讓我們將 `App` 元件拆分為更小的元件。我們首先將影片清單提取到自己的組件中。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n注意我們的 `VideosList` 函數元件的參數。函數元件只接受一個參數，該參數定義了它的 \"props\"（\"properties\" 的縮寫）。 Props 用於從父元件傳遞資料到子元件。在這種情況下，`VideosListProps` 是一個定義 props 的結構體。\n\n:::important\n用於 props 的結構體必須透過派生實作 `Properties`。\n:::\n\n為了讓上面的程式碼編譯通過，我們需要修改 `Video` 結構體如下：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n現在，我們可以更新我們的 `App` 元件以使用 `VideosList` 元件。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n透過查看瀏覽器窗口，我們可以驗證清單是否按預期呈現。我們已經將清單的渲染邏輯移動到了它的元件中。這縮短了 `App` 元件的原始程式碼，使我們更容易閱讀和理解。\n\n### 使應用程式可以交互\n\n這裡的最終目標是顯示所選影片。為了做到這一點，`VideosList` 元件需要在選擇影片時「通知」其父元件，這是透過 `Callback` 完成的。這個概念稱為「傳遞處理程序」。我們修改其 props 以接受一個 `on_click` 回呼：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n然後我們修改 `VideosList` 元件以將所選影片傳遞給回呼。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n接下來，我們需要修改 `VideosList` 的使用以傳遞該回呼。但在這樣做之前，我們應該建立一個新的元件 `VideoDetails`，當點擊影片時才會顯示。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n現在，修改 `App` 元件以在選擇影片時顯示 `VideoDetails` 元件。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n現在不用擔心 `use_state`，我們稍後會回到這個問題。注意我們用 `{ for details }` 提取列表資料的技巧。\n`Option<_>` 實作了`Iterator`，所以我們可以使用特殊的`{ for ... }` 語法來逐個顯示`Iterator` 返回的唯一元素，而這[由`html!` 巨集支援](concepts/html/lists)。\n\n### 處理狀態\n\n還記得之前使用的 `use_state` 嗎？那是一個特殊的函數，稱為 \"hook\"。 Hooks 用於 \"hook\" 到函數元件的生命週期中並執行操作。您可以在[這裡](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)了解更多關於這個 hook 和其他 hook 的資訊。\n\n:::note\n結構體組件的行為不同。請查看[文件](advanced-topics/struct-components/introduction.mdx)以了解有關這些的資訊。\n:::\n\n## 取得資料（使用外部 REST API）\n\n在真實的應用程式中，資料通常來自 API 而不是硬編碼。讓我們從外部來源取得我們的影片清單。為此，我們需要添加以下 crate：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  用於進行 fetch 調用。\n- [`serde`](https://serde.rs) 及其衍生特性\n  用於反序列化 JSON 回應\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  用於將 Rust 的 Future 作為 Promise 執行\n\n讓我們更新 `Cargo.toml` 檔案中的依賴項：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n在選擇依賴項時，請確保它們與 `wasm32` 相容！否則，您將無法運行您的應用程式。\n:::\n\n更新 `Video` 結構體以衍生 `Deserialize` 特性：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n最後一步，我們需要更新我們的 `App` 元件，以便進行 fetch 請求，而不是使用硬編碼的數據\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\n我們在這裡使用 `unwrap`，因為這是一個演示應用程式。在真實的應用程式中，您可能希望有[適當的錯誤處理](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)。\n:::\n\n現在，查看瀏覽器，看看一切是否按預期工作……如果不是因為 CORS 的話。為了解決這個問題，我們需要一個代理伺服器。幸運的是 trunk 提供了這個功能。\n\n更新這些行：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n現在，使用以下命令重新運行伺服器：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\n刷新網頁，一切都應該按預期工作。\n\n## 總結\n\n恭喜！您已經建立了一個從外部 API 取得資料並顯示影片清單的 Web 應用程式。\n\n## 接下來\n\n這個應用程式離完美或有用還有很長的路要走。完成本教學後，您可以將其作為探索更高級主題的起點。\n\n### 樣式\n\n我們的應用程式看起來非常醜陋。沒有 CSS 或任何樣式。不幸的是，Yew 沒有提供內建的樣式組件。請查看 [Trunk 的 assets](https://trunkrs.dev/assets/)，以了解如何新增樣式表。\n\n### 更多依賴函式庫\n\n我們的應用程式只使用了很少的外部依賴。有很多 crate 可以使用。請查看[外部程式庫](/community/external-libs)以取得更多詳細資訊。\n\n### 了解更多關於 Yew\n\n閱讀我們的[官方文件](../getting-started/introduction.mdx)。它更詳細地解釋了許多概念。要了解有關 Yew API 的更多信息，請查看我們的[API 文件](https://docs.rs/yew)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.22.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.22\",\n    \"description\": \"The label for version 0.22\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"從零開始\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"核心觀念\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Function Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"進階主題\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"進階主題\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"更多\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Intro With Basic Web Technologies\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew mostly operates on the idea of keeping everything that a reusable piece of UI may need, in one place - rust files. But also seeks to stay close to the original look of the technology. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/children.mdx",
    "content": "---\ntitle: '子組件'\n---\n\n:::caution\n\n檢查和操作 `Children` 往往會導致應用程式中令人驚訝且難以解釋的行為。這可能導致邊緣情況，並且通常不會產生預期的結果。如果您嘗試操作 `Children`，則應考慮其他方法。\n\nYew 支援將 `Html` 用作子元件屬性的類型。如果您不需要 `Children` 或 `ChildrenRenderer`，則應使用 `Html` 作為子元件。它沒有 `Children` 的缺點，且效能開銷較低。\n\n:::\n\n## 一般用法\n\n*大多數情況下，*當允許元件具有子元件時，您不關心元件具有的子元件的類型。在這種情況下，下面的範例就足夠了。\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## 進階用法\n\n### 類型化子元件\n\n在您希望將一種類型的元件作為子元件傳遞給您的元件的情況下，您可以使用 `yew::html::ChildrenWithProps<T>`。\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## 帶有屬性的巢狀子元件\n\n如果包含元件對其子元件進行了類型化，則可以存取和變更巢狀元件的屬性。\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### 枚舉類型的子元件\n\n當然，有時您可能需要將子元件限制為幾種不同的元件。在這些情況下，您必須更深入地了解 Yew。\n\n這裡使用 [`derive_more`](https://github.com/JelteF/derive_more) 來提供更好的人體工學。如果您不想使用它，您可以為每個變體手動實現 `From`。\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// 現在，我們實現 `Into<Html>`，以便 yew 知道如何渲染 `Item`。\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### 可選類型的子元件\n\n您也可以具有特定類型的單一可選子元件：\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... 页面内容\n            </div>\n        }\n    }\n}\n\n// 页面组件可以选择是否附带侧边栏：\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // 附带侧边栏的页面\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // 不附带侧边栏的页面\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## 進一步閱讀\n\n- 有關此模式的真實範例，請查閱 yew-router 的原始程式碼。有關更高級的範例，請查看 yew 儲存庫中的[相關範例清單](https://github.com/yewstack/yew/tree/master/examples/nested_list)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: '工作原理'\ndescription: '關於框架的底層細節'\n---\n\n# 底層庫的內部細節\n\n## `html!` 巨集的內部\n\n`html!` macro 會將使用類似 HTML 的自訂語法所編寫的程式碼轉換為有效的 Rust 程式碼。使用這個巨集對於開發 Yew 應用程式並不是必需的，但是是建議的。這個巨集產生的程式碼使用了 Yew 的公共函式庫 API，如果你願意的話，可以直接使用。請注意，有些方法是有意未記錄的，以避免意外的誤用。隨著 `yew-macro` 的每次更新，產生的程式碼將會更加高效，並且可以處理任何破壞性的更改，而不需要對 `html!` 語法進行很多（如果有的話）修改。\n\n由於 `html!` 巨集允許您以聲明式的風格編寫程式碼，因此您的 UI 佈局程式碼將與為頁面產生的 HTML 非常相似。隨著您的應用程式變得更加互動式，您的程式碼庫變得更大，這種方式變得越來越有用。與手動編寫所有操作 DOM 的程式碼相比，巨集會為您處理好這一切。\n\n使用 `html!` 巨集可能會讓人感到非常神奇，但它並沒有什麼可隱藏的。如果您對它的工作原理感到好奇，可以嘗試展開您程式中的 `html!` 巨集呼叫。有一個有用的指令叫做 `cargo expand`，它允許您查看 Rust 巨集的展開。 `cargo expand` 並不是預設隨 `cargo` 一起提供的，所以如果您還沒有安裝它，您需要使用 `cargo install cargo-expand` 來安裝它。 [Rust-Analyzer](https://rust-analyzer.github.io/) 也提供了一個[從IDE 中取得巨集輸出的機制](https://rust-analyzer.github.io/manual.html #expand-macro-recursively)。\n\n`html!` 巨集的輸出通常非常簡潔！這是一個功能：機器產生的程式碼有時可能會與應用程式中的其他程式碼衝突。為了防止問題，`proc_macro` 遵循了「衛生」規則。一些例子包括：\n\n1. 為了確保正確引用 Yew 套件，巨集產生的程式碼中使用 `::yew::<module>`，而不是直接使用 `yew::<module>`。這也是為什麼呼叫 `::alloc::vec::Vec::new()` 而不是直接呼叫 `Vec::new()`。\n2. 由於可能有 trait 方法名稱衝突，使用 `<Type as Trait>` 來確保我們使用的是正確的 trait 成員。\n\n## 什麼是虛擬 DOM？\n\nDOM（\"文件物件模型\"）是由瀏覽器管理的 HTML 內容的表示。 \"虛擬\" DOM 只是 DOM 的一個記憶體中的副本。管理虛擬 DOM 會導致更高的記憶體開銷，但可以透過避免或延遲使用瀏覽器 API 來實現批次和更快的讀取。\n\n在記憶體中擁有 DOM 的副本對於促進使用聲明式 UI 的函式庫是有幫助的。與需要特定程式碼來描述如何根據使用者事件修改 DOM 不同，程式庫可以使用一種通用的方法來進行 DOM \"diffing\"。當 Yew 元件更新並希望更改其呈現方式時，Yew 庫將建立虛擬 DOM 的第二個副本，並直接將其與鏡像當前螢幕上的內容的虛擬 DOM 進行比較。兩者之間的 \"diff\"（差異）可以分解為增量更新，並與瀏覽器 API 一起應用。一旦更新應用，舊的虛擬 DOM 副本將被丟棄，新的副本將被保存以供將來的差異檢查。\n\n這種 \"diff\" 演算法可以隨著時間的推移進行最佳化，以提高複雜應用程式的效能。由於 Yew 應用程式是透過 WebAssembly 運行的，我們相信 Yew 在未來採用更複雜的演算法方面具有競爭優勢。\n\nYew 的虛擬 DOM 與瀏覽器 DOM 不完全一一對應。它還包括用於組織 DOM 元素的 \"列表\" 和 \"元件\"。列表可以簡單地是元素的有序列表，但也可以更強大。透過為每個清單元素新增 \"key\" 註解，應用程式開發人員可以幫助 Yew 進行額外的最佳化，以確保在清單變更時，計算差異更新所需的工作量最小。同樣，元件提供了自訂邏輯，指示是否需要重新渲染，以幫助提高效能。\n\n## Yew 調度器和元件範圍的事件循環\n\n_貢獻文件 - 深入解釋 `yew::scheduler` 和 `yew::html::scope` 的工作原理_\n\n## 進一步閱讀\n\n- [Rust 手冊中關於巨集的更多資訊](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [`cargo-expand` 的更多資訊](https://github.com/dtolnay/cargo-expand)\n- [`yew::virtual_dom` 的 API 文件](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/immutable.mdx",
    "content": "---\ntitle: '不可變型別'\ndescription: 'Yew 的不可變資料結構'\n---\n\n## 什麼是不可變型別？\n\n這些類型是您可以實例化但永遠不會更改值的類型。為了更新值，您必須實例化一個新值。\n\n## 為什麼使用不可變型別？\n\n與 React 一樣，屬性是從祖先傳播到子代的。這意味著屬性在每個元件更新時必須存在。這就是為什麼屬性應該——理想情況下——很容易克隆。為了實現這一點，我們通常將事物包裝在 `Rc` 中。\n\n不可變類型非常適合保存屬性的值，因為它們可以在從組件傳遞到組件時以很低的成本克隆。\n\n## 常見的不可變型別\n\nYew 推薦使用來自 `implicit-clone` crate 的以下不可變型別：\n\n- `IString`（在 Yew 中別名為 `AttrValue`）- 用於字串而不是 `String`\n- `IArray<T>` - 用於陣列/向量而不是 `Vec<T>`\n- `IMap<K, V>` - 用於映射而不是 `HashMap<K, V>`\n\n這些型別是引用計數（`Rc`）或靜態引用，使它們的克隆成本非常低。\n\n## 進一步閱讀\n\n- [不可變範例](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: '優化 & 最佳實踐'\nsidebar_label: Optimizations\ndescription: '讓您的應用程式獲得最佳效能'\n---\n\n## 使用智慧指針\n\n**注意：如果您對本節中使用的某些術語感到困惑，Rust 手冊中有一個有用的[關於智慧型指針的章節](https://doc.rust-lang.org/book/ch15-00- smart-pointers.html)。 **\n\n為了避免在重新渲染時克隆大量資料以創建 props，我們可以使用智慧指針，只克隆對資料的引用而不是資料本身。如果您在props 和子組件中傳遞與相關數據的引用而不是實際數據，您可以避免在需要修改數據的子組件中克隆任何數據，您可以使用`Rc::make_mut` 來克隆並獲得要更改的數據的可變引用。\n\n這在 `Component::changed` 中帶來了更多好處，可以確定 prop 變更是否需要元件重新渲染。這是因為可以比較指標位址（即資料儲存在機器記憶體中的位置）而不是資料的值；如果兩個指標指向相同的數據，則它們指向的資料的值必須相同。請注意，反之可能不成立！即使兩個指標位址不同，底層資料仍可能相同 - 在這種情況下，您應該比較底層資料。\n\n要進行此比較，您需要使用 `Rc::ptr_eq` 而不僅使用 `PartialEq`（在使用相等運算子 `==` 比較資料時自動使用）。 Rust 文件有關於 `Rc::ptr_eq` 的[更多細節](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。\n\n這種最佳化對於不實作 `Copy` 的資料類型最有用。如果您可以廉價地複製數據，則沒有必要將其放在智慧指標後面。對於可能是資料密集的結構，如 `Vec`、`HashMap` 和 `String`，使用智慧指標可能會帶來效能改進。\n\n如果數值從不被子元件更新，則此最佳化效果最佳，如果父元件很少更新，則效果更佳。這使得 `Rc<_>` 是在純元件中包裝屬性值的一個不錯的選擇。\n\n但是，必須注意，除非您需要在子元件中自己克隆數據，否則這種最佳化不僅是無用的，而且還增加了不必要的引用計數成本。 Yew 中的 props 已經是引用計數的，內部不會發生資料克隆。\n\n## 渲染函數\n\n出於程式碼可讀性的原因，將 `html!` 的部分重複程式碼遷移到專門分割出來的函數中通常是有意義的。這不僅使您的程式碼更易讀，減少了程式碼縮進，而且還鼓勵良好的設計模式——特別是圍繞構建可組合應用程序，這些函數可以在多個地方調用，從而減少程式碼量。\n\n## 純組件\n\n純組件是不會改變其狀態的元件，只顯示內容並將訊息傳播到普通的可變組件。它們與視圖函數的不同之處在於，它們可以在`html!` 巨集中使用元件語法（`<SomePureComponent />`）而不是表達式語法（`{some_view_function()}`），並且根據其實現，它們可以被記憶化（這意味著一旦調用函數，其值就會被“保存”，因此如果多次使用相同的參數調用它，則不必重新計算其值，只需從第一個函數調用返回保存的值）- 防止相同的props 重新渲染。 Yew 在內部比較 props，因此僅在 props 更改時重新渲染 UI。\n\n## 使用工作區減少編譯時間\n\nYew 的最大缺點是編譯所需的時間很長。編譯專案所需的時間似乎與傳遞給 `html!` 巨集的程式碼數量有關。對於較小的項目，這似乎不是什麼問題，但對於較大的應用程序，將程式碼拆分到多個 crate 中以最小化編譯器為應用程式所做的工作量是有意義的。\n\n一種可能的方法是使您的主 crate 處理路由/頁面選擇，然後為每個頁面建立一個不同的 crate，其中每個頁面可以是不同的元件或只是產生 `Html` 的大函數。儲存在包含應用程式不同部分的 crate 之間的程式碼可以儲存在專案依賴的單獨 crate 中。在最理想的情況下，您從每次編譯時重新建置所有程式碼到僅重新建置主 crate 和一個頁面 crate。在最壞的情況下，如果您在「common」 crate 中編輯了某些內容，您將回到起點：編譯依賴於該常用共享 crate 的所有程式碼，這可能是其他所有內容。\n\n如果您的主crate 太重，或者您想快速迭代一個深度巢狀的頁面（例如。在另一個頁面上渲染的頁面），您可以使用範例crate 建立主頁面的簡化實現，並額外渲染您正在處理的組件。\n\n## 減少二進位檔案大小\n\n- 優化 Rust 程式碼\n- `cargo.toml`（定義發布設定檔）\n- 使用 `wasm-opt` 最佳化 wasm 程式碼\n\n**注意：有關減小二進位檔案大小的更多信息，請參閱[Rust Wasm 手冊](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code -size)。 **\n\n### Cargo.toml\n\n可以使用 `Cargo.toml` 中 `[profile.release]` 部分中的可用設定來配置發佈建置為更小。\n\n```toml, title=Cargo.toml\n[profile.release]\n# 讓二進位檔案尺寸更小些\npanic = 'abort'\n# 優化整個程式碼庫（優化更好，但建置速度也會更慢）\ncodegen-units = 1\n# 優化尺寸（更激進的做法）\nopt-level = 'z'\n# 優化尺寸\n# opt-level = 's'\n# 使用程式整體分析時進行連結時優化\nlto = true\n```\n\n### 開發版 Cargo 配置\n\n您還可以從 Rust 和 cargo 的實驗性開發版功能中獲得額外的好處。若要使用 `trunk` 的開發版工具鏈，請設定 `RUSTUP_TOOLCHAIN=\"nightly\"` 環境變數。然後，您可以在 `.cargo/config.toml` 中配置不穩定的 rustc 功能。請參考[不穩定功能]的文檔，特別是關於[`build-std`]和[`build-std-features`]的部分，以了解配置。\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# 需要 rust-src 組件。`rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[不穩定特性列表]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\n開發版 Rust 編譯器可能包含錯誤，例如[這個例子](https://github.com/yewstack/yew/issues/2696)，需要偶爾注意和調整。請謹慎使用這些實驗性選項。\n:::\n\n### wasm-opt\n\n此外，可以最佳化 `wasm` 程式碼的大小。\n\nRust Wasm 手冊中有關於減少 Wasm 二進位檔案大小的部分：[縮小 .wasm 大小](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- 使用 `wasm-pack`，預設會最佳化發佈建置中的 `wasm` 程式碼\n- 直接在 `wasm` 檔案上使用 `wasm-opt`\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### 在 yew/examples/ 中 'minimal' 範例的建置大小\n\n注意：`wasm-pack` 結合了 Rust 和 Wasm 程式碼的最佳化。在此範例中，`wasm-bindgen` 未經任何 Rust 大小最佳化。\n\n| 工具鏈                      | 大小  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## 進一步閱讀\n\n- [Rust 手冊中關於智慧型指標的章節](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Rust Wasm 手冊中關於減小二進位檔案大小的資訊](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Rust 設定檔的文件](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen 專案](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/portals.mdx",
    "content": "---\ntitle: '傳送門 (Portals)'\ndescription: '將內容渲染到 DOM 樹外的節點'\n---\n\n## 什麼是 Portal？\n\n傳送門 (Portal) 提供了一種將子元素渲染到父元件的 DOM 層次結構以外的 DOM 節點的方法。 `yew::create_portal(child, host)` 傳回一個 `Html` 值，它將 `child` 渲染為 `host` 元素的子元素，而不是在其父元件的層次結構下。\n\n## 用法\n\n傳送門的典型用途包括模態對話框和懸停卡片，以及更多技術應用，例如控制元素的[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API /Element/shadowRoot) 的內容，將樣式表附加到周圍文檔的`<head>` 中，以及在`<svg>` 的中央`<defs>` 元素中收集引用的元素。\n\n請注意，`yew::create_portal` 是一個低階建置區塊。庫應該使用它來實現更高級的 API，然後應用程式可以使用這些 API。例如，這裡是一個簡單的模態對話框，它將其 `children` 渲染到 `yew` 以外的元素中，該元素由 `id=\"modal_host\"` 標識。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## 事件處理\n\n傳送門內部元素上發出的事件遵循虛擬 DOM 冒泡。也就是說，如果傳送門被渲染為元素的子元素，那麼該元素上的事件監聽器將捕捉從傳送門內部分發出的事件，即使傳送門將其內容渲染在實際 DOM 中的不相關位置。\n\n這使開發人員無需關心他們使用的組件是使用傳送門實現的還是沒有使用傳送門實現的。無論如何，其子元素上觸發的事件都會冒泡。\n\n已知問題是，從傳送門到 **關閉** 的 shadow root 的事件將被分發兩次，一次針對 shadow root 內部的元素，一次針對宿主元素本身。請記住，**打開** 的 shadow root 可以正常工作。如果這影響到您，請隨時提交錯誤報告。\n\n## 進一步閱讀\n\n- [傳送門範例](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: '服務端渲染'\ndescription: '在服務端渲染 Yew 元件。 '\n---\n\n# 服務端渲染 (Server-Side Rendering)\n\n預設情況下，Yew 元件在客戶端渲染。當使用者造訪一個網站時，伺服器會傳送一個骨架 HTML 文件，不包含任何實際內容，以及一個 WebAssembly 套件給瀏覽器。所有內容都由 WebAssembly 套件在客戶端渲染。這被稱為客戶端渲染。\n\n這種方法對於大多數網站來說都是有效的，但有一些注意事項：\n\n1. 使用者在整個 WebAssembly 套件下載並完成初始渲染之前將看不到任何內容。這可能會導致在緩慢的網路上用戶體驗不佳。\n2. 有些搜尋引擎不支援動態渲染的網頁內容，而那些支援的搜尋引擎通常會將動態網站排名較低。\n\n為了解決這些問題，我們可以在服務端渲染我們的網站。\n\n## 工作原理\n\nYew 提供了一個 `ServerRenderer` 來在服務端渲染頁面。\n\n要在服務端渲染Yew 元件，您可以使用`ServerRenderer::<App>::new()` 建立一個渲染器，並呼叫`renderer.render().await` 將`<App />` 渲染為一個`String`。\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// 我們在使用 `flavor = \"current_thread\"` 以確保這個範例可以在 CI 中的 WASM 環境運作,\n// 如果你希望使用多執行緒的話，可以使用預設的 `#[tokio::main]` 宏\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // 列印: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## 組件生命週期\n\n與客戶端渲染不同，元件的生命週期在服務端渲染時會有所不同。\n\n在元件成功第一次渲染為 `Html` 之前，除了 `use_effect` (和 `use_effect_with`) 之外的所有鉤子都會正常運作。\n\n:::caution 瀏覽器介面不可用！\n\n瀏覽器相關的接口，如 `web_sys`，在元件在服務端渲染時是不可用的。如果您嘗試使用它們，您的應用程式將會崩潰。您應該將需要這部分邏輯隔離在 `use_effect` 或 `use_effect_with` 中，因為在服務端渲染時它們無法也不應執行。\n\n:::\n\n:::danger 結構化組件\n\n儘管可以在服務端渲染時使用結構化元件，但是在客戶端安全邏輯（如函數元件的`use_effect` 鉤子）和生命週期事件之間沒有明確的邊界，並且生命週期事件的呼叫順序與客戶端不同。\n\n此外，結構化元件將繼續接受訊息，直到所有子元件都被渲染並呼叫了 `destroy` 方法。開發人員需要確保不會將可能傳遞給元件的訊息連結到呼叫瀏覽器介面的邏輯。\n\n在設計支援服務端渲染的應用程式時，請盡量使用函數元件，除非您有充分的理由不這樣做。\n\n:::\n\n## 服務端渲染期間的資料獲取\n\n資料取得是服務端渲染和水合（hydration）期間的困難之一。\n\n在傳統做法中，當一個元件渲染時，它會立即可用（輸出一個虛擬 DOM 以進行渲染）。當元件不需要取得任何資料時，這種方式是有效的。但是如果元件在渲染時想要取得一些資料會發生什麼事呢？\n\n過去，Yew 沒有機制來檢測組件是否仍在取得資料。資料擷取用戶端負責實作一個解決方案，以偵測在初始渲染期間請求了什麼，並在請求完成後觸發第二次渲染。伺服器會重複這個過程，直到在回傳回應之前沒有在渲染期間添加更多的掛起請求。\n\n這不僅浪費了CPU 資源，因為重複渲染元件，而且資料用戶端還需要提供一種方法，在水合過程中使在服務端獲取的資料可用，以確保初始渲染返回的虛擬DOM 與服務端渲染的DOM樹一致，這可能很難實現。\n\nYew 採用了不同的方法，透過 `<Suspense />` 來解決這個問題。\n\n`<Suspense />` 是一個特殊的元件，當在客戶端使用時，它提供了一種在元件獲取資料（掛起）時顯示一個回退UI 的方法，並在資料獲取完成後恢復到正常UI。\n\n當應用程式在服務端渲染時，Yew 會等待元件不再掛起，然後將其序列化到字串緩衝區中。\n\n在水合過程中，`<Suspense />` 組件中的元素保持未水合狀態，直到所有子組件不再掛起。\n\n透過這種方法，開發人員可以輕鬆建立一個準備好進行服務端渲染的、與客戶端無關的應用程序，並進行資料擷取。\n\n## 渲染 `<head>` 標籤\n\nSSR 中的一個常見需求是渲染動態 `<head>` 內容（例如 `<title>`、`<meta>`），使爬蟲和社群預覽在首次載入時能看到正確的中繼資料。\n\n`ServerRenderer` 只渲染元件樹（通常對應文件的 body 部分），無法存取 `<head>`。因此，head 標籤必須**在伺服器端、Yew 之外**產生，並在傳送給客戶端之前拼接到 HTML 範本中。\n\n[`ssr_router` 範例](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) 展示了這個模式：伺服器從請求 URL 識別路由，產生適當的 `<title>` 和 `<meta>` 標籤，並將它們注入到 Trunk 產生的 `index.html` 的 `</head>` 之前。\n\n:::info\n\n如需完全相容 SSR 的第三方解決方案，請使用 [Bounce 的 `<Helmet/>` 元件](https://docs.rs/bounce/latest/bounce/helmet/index.html)。\n\n:::\n\n## SSR 水合（SSR Hydration）\n\n水合是將 Yew 應用程式連接到服務端產生的 HTML 檔案的過程。預設情況下，`ServerRender` 會列印可水合的 HTML 字串，其中包含額外的資訊以便於水合。當呼叫 `Renderer::hydrate` 方法時，Yew 不會從頭開始渲染，而是將應用程式產生的虛擬 DOM 與伺服器渲染器產生的 HTML 字串進行協調。\n\n:::caution\n\n要成功對由 `ServerRenderer` 建立的 HTML 標記進行水合，用戶端必須產生一個虛擬 DOM 佈局，它與用於 SSR 的佈局完全匹配，包括不包含任何元素的元件。如果您有任何只在一個實作中有用的元件，您可能想要使用 `PhantomComponent` 來填入額外元件的位置。\n:::\n\n:::warning\n\n只有在瀏覽器初始渲染 SSR 輸出（靜態 HTML）後，真實 DOM 與預期 DOM 相符時，水合才能成功。如果您的 HTML 不符合規範，水合可能會失敗。瀏覽器可能會更改不正確的 HTML 的 DOM 結構，導致實際 DOM 與預期 DOM 不同。例如，[如果您有一個沒有`<tbody>` 的`<table>`，瀏覽器可能會向DOM 添加一個`<tbody>`](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## 水合期間的組件生命週期\n\n在水合期間，元件在創建後安排了 2 次連續的渲染。任何效果都是在第二次渲染完成後調用的。確保您的元件的渲染函數沒有副作用是很重要的。它不應該改變任何狀態或觸發額外的渲染。如果您的元件目前改變狀態或觸發額外的渲染，請將它們移到 `use_effect` 鉤子中。\n\n在水合過程中，可以使用結構化元件進行服務端渲染，視圖函數將在渲染函數之前被調用多次。直到呼叫渲染函數之前，DOM 被認為是未連接的，您應該防止在呼叫 `rendered()` 方法之前存取渲染節點。\n\n## 範例\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // 對 body 元素下的所有內容進行水合，並移除可能有的任何尾隨元素。\n    renderer.hydrate();\n}\n```\n\n範例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\n範例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## 單線程模式\n\nYew 支援以單一執行緒進行服務端渲染，透過 `yew::LocalServerRenderer`。這種模式適用於像 WASI 這樣的單執行緒環境。\n\n```rust\n// 使用 `wasm32-wasip1` 或 `wasm32-wasip2` 目標建置。\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\n範例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\n如果您使用 `wasm32-unknown-unknown` 目標建立 SSR 應用程序，您可以使用 `not_browser_env` 功能標誌來停用 Yew 內部對特定於瀏覽器的 API 的存取。這在像 Cloudflare Worker 這樣的無伺服器平台上非常有用。\n:::\n\n:::caution\n\n服務端渲染目前是實驗性的。如果您發現了一個 bug，[請在 GitHub 回饋](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: '回呼函數 (Callbacks)'\n---\n\n## 回呼函數 (Callbacks)\n\n回調函數是用於在 Yew 中與服務、代理和父元件進行通訊的。在內部，它們的類型只是 `Fn` 包裝在 `Rc` 中，以允許它們被克隆。\n\n它們有一個 `emit` 函數，該函數以其 `<IN>` 類型作為參數，並將其轉換為其目標期望的訊息。如果父元件中的回呼函數作為 props 提供給子元件，子元件可以在其 `update` 生命週期鉤子中呼叫回呼函數的 `emit` 函數，以將訊息傳回其父元件。在 `html!` 巨集中作為 props 提供的閉包或函數會自動轉換為回呼函數。\n\n一個簡單的回呼函數的使用可能如下所示：\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\n這個函數傳遞給 `callback` 必須永遠帶有一個參數。例如，`onclick` 處理程序需要一個接受 `MouseEvent` 類型參數的函數。然後處理程序可以決定應該發送什麼類型的消息給組件。這個訊息無條件地被安排在下一個更新循環中。\n\n如果你需要一個回呼函數，它可能不需要引起更新，請使用 `batch_callback`。\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## 相關範例\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: '高階組件'\n---\n\n在某些情況下，結構組件不直接支援某些功能（例如 Suspense），或使用某些功能需要大量的樣板程式碼（例如 Context）。\n\n在這些情況下，建議建立高階組件的函數組件。\n\n## 高階組件定義\n\n高階元件是不添加任何新 HTML 的元件，只是包裝其他元件以提供額外功能。\n\n### 範例\n\n對 Context (上下文) 掛鉤並將其傳遞給結構組件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: '簡介'\ndescription: 'Yew 中的元件'\n---\n\n## 什麼是元件？\n\n組件是 Yew 的構建塊。它們管理內部狀態並可以將元素渲染到 DOM 中。透過為類型實作 `Component` trait 來建立元件。\n\n## 編寫元件標記\n\nYew 使用虛擬 DOM 將元素渲染到 DOM 中。虛擬 DOM 樹可以透過使用 `html!` 巨集來建構。 `html!` 使用的語法類似 HTML，但並不相同。規則也更嚴格。它還提供了條件渲染和使用迭代器渲染清單等超能力。\n\n:::info\n[了解更多關於 `html!` 宏，如何使用它以及它的語法](concepts/html/introduction.mdx)\n:::\n\n## 將資料傳遞給元件\n\nYew 元件使用 _props_ 在父元件和子元件之間通訊。父元件可以將任何資料作為 props 傳遞給其子元件。 Props 類似於 HTML 屬性，但可以將任何 Rust 類型作為 props 傳遞。\n\n:::info\n[了解更多關於 props 的內容](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\n對於除了父/子通信之外的其他通信，請使用 [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: '生命週期'\ndescription: '元件及其生命週期鉤子'\n---\n\n`Component` trait 有許多方法需要實作；Yew 會在元件的生命週期的不同階段呼叫這些方法。\n\n## 生命週期\n\n:::important 改進文檔\n`為文件做貢獻：` [新增自訂生命週期的組件範例](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## 生命週期方法\n\n### Create\n\n當元件被建立時，它會從其父元件接收屬性，並儲存在傳遞給 `create` 方法的 `Context<Self>` 中。這些屬性可以用來初始化元件的狀態，而 \"link\" 可以用來註冊回呼或傳送訊息給元件。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具體實現\n        }\n    }\n}\n```\n\n### View\n\n`view` 方法可讓您描述元件應該如何呈現到 DOM 中。使用Rust 函數編寫類似HTML 的程式碼可能會變得非常混亂，因此Yew 提供了一個名為`html!` 的宏，用於聲明HTML 和SVG 節點（以及將屬性和事件監聽器附加到它們）以及一種方便的方法來渲染子元件。這個宏在某種程度上類似於 React 的 JSX（除了程式語言的差異）。一個不同之處是 Yew 提供了一種類似 Svelte 的屬性的簡寫語法，其中您可以只寫 `{onclick}`，而不用寫 `onclick={onclick}`。\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\n就使用上的說明，請查看 [html! 指南](concepts/html/introduction.mdx)。\n\n### Rendered\n\n`rendered` 元件生命週期方法在 `view` 被調用並且 Yew 已經將結果渲染到 DOM 中後調用，但在瀏覽器刷新頁面之前。當您想要執行只能在元件渲染元素後完成的操作時，此方法非常有用。還有一個名為 `first_render` 的參數，可以用來確定此函數是在第一次渲染時調用，還是在後續渲染時調用。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\n請注意，此生命週期方法不需要實現，並且預設不會執行任何操作。\n:::\n\n### Update\n\n與組件的通訊主要透過訊息進行，這些訊息由 `update` 生命週期方法處理。這允許元件根據訊息更新自身，並確定是否需要重新渲染自身。訊息可以由事件監聽器、子元件、Agents、Services 或 Futures 傳送。\n\n下面是 `update` 的實作範例：\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // 重新渲染\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // 具體實現\n        }\n    }\n\n}\n```\n\n### Changed\n\n元件可能會被其父元件重新渲染。當這種情況發生時，它們可能會接收新的屬性並需要重新渲染。這種設計透過僅更改屬性的值來促進父子組件之間的通訊。當屬性更改時，有一個預設實作會重新渲染元件。\n\n### Destroy\n\n元件從 DOM 卸載後，Yew 會呼叫 `destroy` 生命週期方法；如果您需要在元件被銷毀之前執行清理操作，這是必要的。此方法是可選的，預設不執行任何操作。\n\n### 無限循環\n\n無限循環在 Yew 的生命週期方法中是可能的，但只有在嘗試在每次渲染後更新相同的元件時，當更新也要求重新渲染元件時才會發生。\n\n下面是一個簡單的範例：\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // 我們總是請求在任何訊息上重新渲染\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // 無論渲染什麼都不重要\n        Html::default()\n        }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // 請求使用此新訊息更新元件\n        ctx.link().send_message(());\n    }\n}\n```\n\n讓我們看看這裡發生了什麼：\n\n1. 使用 `create` 函數建立元件。\n2. 呼叫 `view` 方法，以便 Yew 知道要渲染到瀏覽器 DOM 中的內容。\n3. 呼叫 `rendered` 方法，使用 `Context` 連結安排更新訊息。\n4. Yew 完成後渲染階段。\n5. Yew 檢查已排程的事件，並看到更新訊息佇列不為空，因此處理訊息。\n6. 呼叫 `update` 方法，回傳 `true` 表示發生了變化，元件需要重新渲染。\n7. 跳回第 2 步。\n\n您仍然可以在 `rendered` 方法中安排更新，這通常是有用的，但是在這樣做時，請考慮您的元件將如何終止此循環。\n\n## 關聯類型\n\n`Component` trait 有两个关联类型：`Message` 和 `Properties`。\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\n`Message` 類型用於在事件發生後向元件發送訊息；例如，您可能希望在使用者點擊按鈕或向下捲動頁面時執行某些操作。因為元件通常需要回應多個事件，所以 `Message` 類型通常是一個枚舉，其中每個變體都是要處理的事件。\n\n在組織程式碼庫時，將 `Message` 類型的定義包含在定義元件的相同模組中是明智的。您可能會發現採用一致的命名約定來命名訊息類型很有幫助。一個選項（儘管不是唯一的選項）是將類型命名為 `ComponentNameMsg`，例如，如果您的元件名為 `Homepage`，則可以將類型命名為 `HomepageMsg`。\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` 表示從其父元件傳遞給元件的訊息。此類型必須實作 `Properties` trait（通常透過衍生它）並且可以指定某些屬性是必需的還是可選的。在建立和更新元件時使用此類型。在組件的模組中建立一個名為 `Props` 的結構體，並將其用作組件的 `Properties` 類型是一種常見做法。通常將 \"properties\" 縮寫為 \"props\"。由於 props 是從父元件傳遞下來的，因此應用程式的根元件通常具有 `Properties` 類型為 `()`。如果要為根元件指定屬性，請使用 `App::mount_with_props` 方法。\n\n:::info\n[了解更多關於屬性的資訊](./properties)\n:::\n\n## 生命週期上下文\n\n所有組件生命週期方法都接受一個上下文物件。此物件提供了對元件作用域的引用，允許向元件發送訊息並傳遞給元件的 props。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Props)'\ndescription: '父子元件通訊'\n---\n\n屬性 (Properties) 使子組件和父組件之間能夠進行通訊。每個元件都有一個關聯的屬性類型，用來描述從父元件傳遞下來的內容。理論上，這可以是任何實現了 `Properties` 特性的類型，但實際上，它應該是一個結構體，其中每個字段代表一個屬性。\n\n## 派生宏\n\n無需自己實作 `Properties` 特性，我們可以用 `#[derive(Properties)]` 來自動生成實作。派生 `Properties` 的型別也必須實作 `PartialEq`。\n\n### 欄位屬性\n\n在派生 `Properties` 時，預設情況下所有欄位都是必要的。以下屬性可讓您為屬性提供初始值，除非它們被設定為另一個值。\n\n:::tip\n屬性不會在 Rustdoc 產生的文件中顯示。您的屬性的文檔字串應該說明一個屬性是否是可選的，以及它是否有一個特殊的預設值。\n:::\n\n#### `#[prop_or_default]`\n\n使用欄位類型的預設值使用 `Default` 特性來初始化屬性值。\n\n#### `#[prop_or(value)]`\n\n使用 `value` 來初始化屬性值。 `value` 可以是傳回欄位類型的任何表達式。例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。\n\n#### `#[prop_or_else(function)]`\n\n呼叫 `function` 來初始化屬性值。 `function` 應該有簽章 `FnMut() -> T`，其中 `T` 是欄位類型。\n\n## `PartialEq`\n\n`Properties` 需要實作 `PartialEq`。這樣，Yew 才能比較它們，以便在它們發生變化時呼叫 `changed` 方法。\n\n## 使用 Properties 的效能開銷\n\n內部屬性是基於引用計數的指標儲存的。這意味著只有一個指標被傳遞到元件樹中的屬性，以避免複製整個屬性所帶來的昂貴效能開銷。\n\n:::tip\n使用 `AttrValue`，這是我們提供的自訂屬性值類型，這樣就可以不用 String 或其他類似的需要克隆的類型。\n:::\n\n## 範例\n\n```rust\nuse yew::Properties;\n/// 從 virtual_dom 中導入 AttrValue\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 鏈接必須有一個目標\n    href: AttrValue,\n    /// 還要注意我們使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 鏈接的顏色，默認為 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值為 None，則視圖函數不會指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當視圖函數沒有指定活動時，默認為 true\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建立屬性。\n\n這個巨集使用與結構體表達式相同的語法，只是您不能使用屬性或基本表達式 (`Foo { ..base }`)。類型路徑可以直接指向屬性 (`path::to::Props`)，也可以指向元件的關聯屬性 (`MyComp::Properties`)。\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// 鏈接必須有一個目標\n    href: AttrValue,\n    /// 還要注意我們使用的是 AttrValue 而不是 String\n    text: AttrValue,\n    /// 鏈接的顏色，默認為 `Blue`\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// 如果值為 None，則視圖函數不會指定大小\n    #[prop_or_default]\n    size: Option<u32>,\n    /// 當視圖函數沒有指定活動時，默認為 true\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// 注意此函數接收 href 和 text 作為 String\n    /// 我們可以使用 `AttrValue::from` 將其轉換為 `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: '引用 (Refs)'\ndescription: '實作越界 DOM 存取'\n---\n\n`ref` 關鍵字可以在任何 HTML 元素或元件中使用，以取得附加到該元素的 DOM `Element`。這可以用於在 `view` 生命週期方法之外對 DOM 進行更改。\n\n這對於獲取 canvas 元素或滾動到頁面的不同部分很有用。例如，在元件的 `rendered` 方法中使用 `NodeRef` 允許您在從 `view` 渲染後對 canvas 元素進行繪製呼叫。\n\n文法如下：\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## 相關範例\n\n- [節點引用](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: '作用域'\ndescription: '元件的作用域'\n---\n\n## 元件的 `Scope<_>` 接口\n\n`Scope` 是透過訊息建立回呼並更新自己的機制。我們透過在傳遞給元件的上下文物件上呼叫 `link()` 來獲得對它的參考。\n\n### `send_message`\n\n這個函數可以向元件發送訊息。訊息由 `update` 方法處理，該方法決定元件是否應重新渲染。\n\n### `send_message_batch`\n\n這個函數可以同時向元件發送多個訊息。這類似於 `send_message`，但是如果任何訊息導致 `update` 方法傳回 `true`，則元件將在處理批次中的所有訊息後重新渲染。\n\n如果給定的參數向量為空，則此函數不執行任何操作。\n\n### `callback`\n\n建立一個回調，當執行時將向元件發送訊息。在內部，它將使用提供的閉包返回的訊息呼叫 `send_message`。\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // 建立一個接受一些文本並將其作為 `Msg::Text` 訊息變體發送到元件的回調。\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // 上一行是多餘的冗長，為了更清晰，可以簡化為這樣：\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // 將 `Msg::Text(\"Hello World!\")` 發送到元件。\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // 在這裡放置 HTML\n        }\n    }\n}\n```\n\n### `batch_callback`\n\n建立一個回調，執行時將向元件發送一批訊息。與 `callback` 的區別在於，傳遞給此方法的閉包不必傳回訊息。相反，閉包可以傳回 `Vec<Msg>` 或 `Option<Msg>`，其中 `Msg` 是元件的訊息類型。\n\n`Vec<Msg>` 被視為一批訊息，並在內部使用 `send_message_batch`。\n\n`Option<Msg>` 在值為 `Some` 時呼叫 `send_message`。如果值為 `None`，則不執行任何操作。這可以用於根據情況，不需要更新的情況。\n\n這是透過使用僅為這些類型實現的 `SendAsMessage` trait 來實現的。您可以為自己的類型實作 `SendAsMessage`，這樣可以在 `batch_callback` 中使用它們。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/agents.mdx",
    "content": "---\ntitle: '代理 (Agents)'\ndescription: \"Yew's 的代理系統\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n代理程式 (Agents) 是一種將任務卸載到 Web Workers 的方式。\n\n為了使代理程式能夠並發運行，Yew 使用了 [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。\n\n## 生命週期\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## 代理程式的類型\n\n### 範圍\n\n- 公開 - 在任何給定時間，公共代理的實例最多只有一個。橋樑將在 Web Worker 中產生或連接到已經產生的代理程式。當沒有橋樑連接到此代理時，代理將消失。\n\n- 私有 - 為每個新的橋樑在 Web Worker 中產生一個新的代理程式。這對於將與瀏覽器通訊的共享但獨立的行為從元件中移出是很好的。當連接的橋樑被丟棄時，代理將消失。\n\n- 全域 \\(WIP\\)\n\n## 代理與元件之間的通信\n\n### 通信橋 (Bridges)\n\n通訊橋 (bridge) 是一個元件和代理程式之間的通訊通道。它允許元件向代理發送訊息，並接收來自代理的訊息。\n\n`use_bridge` 鉤子也提供了在函數元件中建立橋樑的功能。\n\n### 派發器 (Dispatchers)\n\n派發器 (Dispatchers) 允許元件和代理程式之間進行單向通信，元件以此方式向代理程式發送訊息。\n\n## 開銷\n\n代理程式使用 Web Workers（即私有和公開）。它們在發送和接收訊息時會產生序列化開銷。代理程式使用 [bincode](https://github.com/bincode-org/bincode) 與其他執行緒通信，因此成本比僅呼叫函數要高得多。\n\n## 進一步閱讀\n\n- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) 範例展示了元件如何向代理程式傳送訊息並接收來自代理程式的訊息。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: '使用 classes! 巨集處理 CSS 類別'\ndescription: '用一個方便的巨集來處理 CSS 類別'\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew 並沒有提供原生的 CSS-in-Rust 解決方案，但透過提供程式設計方式與 HTML `class` 屬性互動的方式來輔助樣式。\n\n## `classes!` 巨集\n\n`classes!` 巨集和相關的 `Classes` 結構簡化了 HTML 類別的使用：\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n更多 CSS 相關的內容請參考[此文檔](../../more/css)。\n\n## 內聯樣式\n\n目前 Yew 並沒有提供特殊的輔助工具來處理透過 `style` 屬性指定的內聯樣式，但你可以像處理其他 HTML 屬性一樣處理它：\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\n更多 CSS 相關的內容請參考[此文檔](../../more/css)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: '使用 html! 巨集處理 HTML'\ndescription: '這是 HTML，但不完全是！ '\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n你可以使用 `html!` 巨集來寫類似 HTML 的表達式。 Yew 會在背景轉換為表達 DOM 的 Rust 程式碼。\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\n類似於格式化表達式，您可以透過使用花括號將周圍上下文的值嵌入 HTML 中：\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\n使用 `html!` 有一個重要的規則 - 您只能傳回一個包裝節點。為了渲染多個元素的列表，`html!` 允許使用空標籤（Fragments）。空標籤是沒有名稱的標籤，它們本身不會產生 HTML 元素。\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// 錯誤：只允許一個根 HTML 元素\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// 修正：使用 HTML 空標籤包裹\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\n更多關於 Yew 和 HTML 的內容請參考[更多 HTML](concepts/html/introduction.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'Javascript 與 Rust'\ndescription: '在 Rust 中使用 JavaScript'\ncomment: '盡量保持文件簡短和簡單。它的目的是讓讀者更容易了解 Yew 中的元件，而不是提供正確的 API 文件'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew 在一個地方集中了一個可重用的 UI 部分可能需要的所有內容 - rust 文件，同時也在必要時保持底層技術的可訪問性。\n\n截至今天，WebAssembly 對於 DOM 互動還不完全支援。這意味著即使在 Yew 中，我們有時也依賴呼叫 JavaScript。接下來是涉及的庫的概述。\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一個在 JavaScript 和 Rust 函數之間建立呼叫橋樑的函式庫和工具。\n\n我們強烈建議您查看他們的[文件](https://wasm-bindgen.github.io/wasm-bindgen/)和我們的[快速指南](./wasm-bindgen.mdx)。\n\n## web-sys\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 為 Web API 提供了綁定，並允許我們以一種經過 Rust 處理和安全的方式編寫 JavaScript 程式碼。\n\n範例：\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\n再次強調，我們強烈建議您查看他們的[文件](https://wasm-bindgen.github.io/wasm-bindgen/)和我們的[快速指南](./web-sys.mdx)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) 是一個在 JavaScript 和 Rust 函數之間建立呼叫橋樑的函式庫和工具。它是由 [Rust 和 WebAssembly 工作小組](https://rustwasm.github.io/) 使用 Rust 建構的。\n\nYew 使用 `wasm-bindgen` 透過一些 crate 與瀏覽器進行互動：\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\n本節將從更抽象的層次探討這些 crate，以便更容易理解和使用 Yew 中的 `wasm-bindgen` API。要了解有關 `wasm-bindgen` 及其相關 crate 的更深入指南，請查看 [`wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/)。\n\n有關上述 crate 的文檔，請查看 [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html)。\n\n:::tip\n使用 `wasm-bindgen` doc.rs 搜尋來尋找已使用 `wasm-bindgen` 匯入的瀏覽器 API 和 JavaScript 類型。\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\n這個 crate 為上面的其他 crate 提供了許多構建塊。在本節中，我們只會涵蓋 `wasm-bindgen` crate 的兩個主要領域，即巨集和一些您會一遍又一遍看到的類型/特性。\n\n### `#[wasm_bindgen]` macro\n\n`#[wasm_bindgen]` 巨集提供了 Rust 和 JavaScript 之間的接口，提供了一個在兩者之間進行轉換的系統。使用這個巨集更為高級，除非您要使用外部 JavaScript 函式庫，否則不應該使用它。 `js-sys` 和 `web-sys` crate 為內建 JavaScript 類型和瀏覽器 API 提供了 `wasm-bindgen` 定義。\n\n讓我們透過一個簡單的範例來使用`#[wasm-bindgen]` 巨集來匯入一些特定版本的[`console.log`](https://developer.mozilla.org/en-US/docs/Web/ API/Console/log) 函數。\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// 首先讓我們手動綁定 `console.log`，而不使用 `web_sys` 的幫助。\n// 在這裡，我們手動寫 `#[wasm_bindgen]` 註解，我們程式的正確性取決於這些註解的正確性！\n#[wasm_bindgen]\nextern \"C\" {\n    // 在這裡使用 `js_namespace` 來綁定 `console.log(..)` 而不是只有 `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // `console.log` 是多態的，所以我們可以使用多個簽章綁定它。\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // 多個參數也是可以的！\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// 使用導入的函數！\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_這個範例是基於 [1.2 使用 console.log 的 `wasm-bindgen` 指引](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html) 改編的。 _\n\n### 模擬繼承\n\n在 JavaScript 類別之間的繼承是 JavaScript 語言的核心特性，DOM（文件物件模型）是圍繞它設計的。當使用 `wasm-bindgen` 匯入類型時，您也可以新增描述它們繼承關係的屬性。\n\n在Rust 中，這種繼承關係使用[`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) 和[`AsRef`](https://doc. rust-lang.org/std/convert/trait.AsRef.html) 特性來表示。這裡舉個例子可能會有所幫助；假設您有三種類型 `A`、`B` 和 `C`，其中 `C` 擴展了 `B`，而 `B` 又擴展了 `A`。\n\n在匯入這些類型時，`#[wasm-bindgen]` 巨集將按照下列方式實作 `Deref` 和 `AsRef` 特性：\n\n- `C` 可以 `Deref` 到 `B`\n- `B` 可以 `Deref` 到 `A`\n- `C` 可以被 `AsRef` 到 `B`\n- `C` 和 `B` 都可以被 `AsRef` 到 `A`\n\n這些實作允許您在 `C` 的實例上呼叫 `A` 的方法，並將 `C` 用作 `&B` 或 `&A`。\n\n需要注意的是，使用`#[wasm-bindgen]` 導入的每種類型都有相同的根類型，您可以將其視為上面範例中的`A`，這種類型是[`JsValue`](#jsvalue)，下面有它的部分。\n\n_[`wasm-bindgen` 指引中的 extends 部分](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\n這是 JavaScript 擁有的物件的表示，這是 `wasm-bindgen` 的根捕獲類型。任何來自`wasm-bindgen` 的型別都是`JsValue`，這是因為JavaScript 沒有強型別系統，因此接受變數`x` 的任何函數都不定義其型別，因此`x` 可以是有效的JavaScript 值；因此`JsValue`。如果您正在使用接受 `JsValue` 的導入函數或類型，那麼任何導入的值在技術上都是有效的。\n\n`JsValue` 可以被函數接受，但該函數可能仍然只接受某些類型，這可能會導致panic - 因此在使用原始`wasm-bindgen` API 時，請檢查導入的JavaScript 的文檔，以確定是否會在該值不是某種類型時引發異常（panic）。\n\n_[`JsValue` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)。 _\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust 有一個強型別系統，而 JavaScript…沒有😞。為了讓 Rust 保持這些強型別但仍然方便，WebAssembly 工作小組提出了一個非常巧妙的特性 `JsCast`。它的工作是幫助您從一個JavaScript \"類型\" 轉換到另一個\"類型\"，這聽起來很模糊，但它意味著如果您有一個類型，您知道它是另一個類型，那麼您可以使用`JsCast ` 的函數從一個型別跳到另一個型別。當使用 `web-sys`、`wasm_bindgen`、`js-sys` 時，了解這個很好的特性 - 您會注意到許多類型將從這些 crate 中實作 `JsCast`。\n\n`JsCast` 提供了轉換的檢查和不檢查方法- 因此在運行時，如果您不確定某個物件是什麼類型，您可以嘗試將其轉換，這將返回可能的失敗類型，如[`Option`] (https://doc.rust-lang.org/std/option/enum.Option.html) 和[`Result`](https://doc.rust-lang.org/std/result/enum.Result. html)。\n\n一個常見的例子是在 [`web-sys`](./web-sys.mdx) 中，當您嘗試取得事件的目標時。您可能知道目標元素是什麼，但[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API 總是會回傳一個[` Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)。\n您需要將其轉換為元素類型，以便呼叫其方法。\n\n```rust\n// 需要先導入這個 Trait\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // 也許目標是一個選擇元素？\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // 做點別的\n        return;\n    }\n\n    // 如果它能確定不是一個選擇元素，那麼我可以肯定它是一個輸入元素！\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\n[`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) 方法是一個檢查的轉換，回傳一個`Option<&T>`，這表示如果轉換失敗，則可以再次使用原始類型，因此傳回`None`。 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 方法將消耗`self`，這是Rust 中`into` 方法的約定，傳回的類型是`Result<T, Self>`。如果轉換失敗，則原始的 `Self` 值將在 `Err` 中傳回。您可以再試一次或對原始類型進行其他操作。\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\n`Closure` 類型提供了一種將 Rust 閉包傳遞到 JavaScript 的方法，出於健全性原因，傳遞給 JavaScript 的閉包必須具有 `'static` 生命週期。\n\n這種類型是一個“句柄”，這意味著每當它被丟棄時，它將使其引用的 JS 閉包無效。在 `Closure` 被丟棄後，對 JS 中閉包的任何使用都會引發異常。\n\n當您使用接受型別[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 的`js-sys` 或`web-sys` API 時，通常會使用`Closure`。在[Events](../html/events.mdx) 頁面的[Using `Closure` 部分](../html/events.mdx#using-closure-verbose) 中可以找到Yew 中使用`Closure` 的範例。\n\n_[`Closure` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\n`js-sys` crate 提供了 JavaScript 標準內建物件的綁定/導入，包括它們的方法和屬性。\n\n這不包括任何 Web API，因為這是 [`web-sys`](./web-sys.mdx) 的作用！\n\n_[`js-sys` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\n`wasm-bindgen-futures` crate 提供了一個橋樑，用於將JavaScript Promise 類型作為Rust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) 進行處理，並包含將Rust Future 轉換為JavaScript Promise 的實用程式。當在 Rust（wasm）中處理非同步或其他阻塞工作時，這可能很有用，並提供了與 JavaScript 事件和 JavaScript I/O 原語互動的能力。\n\n目前這個 crate 中有三個主要介面：\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   一個使用[`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) 建構的類型，然後可以用作`Future<Output=Result<JsValue, JsValue >>`。如果 `Promise` 被解析，這個 `Future` 將解析為 `Ok`，如果 `Promise` 被拒絕，則解析為 `Err`，分別包含 `Promise` 的解析或拒絕值。\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   將 Rust `Future<Output=Result<JsValue, JsValue>>` 轉換為 JavaScript `Promise`。未來的結果將轉換為 JavaScript 中的已解析或已拒絕 `Promise`。\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   在目前執行緒上產生一個 `Future<Output = ()>`。這是在 Rust 中運行 Future 的最佳方法，而不是將其發送到 JavaScript。\n\n_[`wasm-bindgen-futures` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` 將是 Yew 中 `wasm-bindgen-futures` crate 中最常用的部分，因為這有助於使用具有非同步 API 的函式庫。\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // 列印 \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew 還在某些 API 中添加了對 futures 的支持，最值得注意的是您可以創建一個接受 `async` 區塊的 `callback_future` - 這在內部使用了 `spawn_local`。\n\n_[`spawn_local` 文件](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'web-sys crate 為 Web API 提供綁定。 '\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n[`web-sys` crate](https://crates.io/crates/web-sys) 為 Web API 提供綁定。這是從瀏覽器 WebIDL 產生的，這就是為什麼有些名稱如此之長，有些類型如此模糊的原因。\n\n## `web-sys` 中的特性 (features)\n\n`web-sys` crate 中啟用了所有特性可能會為 Wasm 應用程式增加很多冗餘。為了解決這個問題，大多數類型都是透過啟用 features 進行控制的，這樣你只需要包含你的應用程式所需的類型。 Yew 啟用了 `web-sys` 的幾個特性，並在其公共 API 中公開了一些類型。你通常需要自行將 `web-sys` 新增為依賴項。\n\n## `web-sys` 中的繼承\n\n在[模擬繼承](./wasm-bindgen.mdx#simulating-inheritance)部分，你可以了解到 Rust 通常提供了一種模擬 JavaScript 中繼承的方法。這在 `web-sys` 中非常重要，因為了解一個類型上有哪些方法意味著了解它的繼承。\n\n這一部分將查看一個特定的元素，並使用Rust 呼叫[`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) 列出其繼承，直到該值為[`JsValue`](./wasm-bindgen.mdx#jsvalue)。\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement 是 HTML 中的 <textarea>。\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // 注意我們現在已經從 web-sys 類型轉移到內建的 JavaScript 類型，\n    // 這些類型在 js-sys crate 中。\n    let object: &js_sys::Object = event_target.deref();\n\n    // 注意我們現在已經從 js-sys 類型轉移到 wasm-bindgen crate 中的根 JsValue。\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // 這樣使用 deref 意味著我們必須手動遍歷繼承樹。\n    // 但是，您可以在 HtmlTextAreaElement 類型上呼叫 JsValue 方法。\n    assert!(!text_area.is_string());\n\n    // 這個空函數只是為了證明我們可以將 HtmlTextAreaElement 作為 &EventTarget 傳遞。\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // 編譯器將沿著 deref 鏈向下走，以符合這裡的類型。\n    this_function_only_takes_event_targets(&text_area);\n\n    // AsRef 實作可讓您將 HtmlTextAreaElement 視為 &EventTarget。\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[`wasm-bindgen` 指引中的 `web-sys` 繼承](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)_\n\n## `NodeRef` 中的 `Node`\n\nYew 使用 [`NodeRef`](concepts/function-components/node-refs.mdx) 來提供一種方式來保留由 [`html!`](concepts/html/introduction.mdx) 巨集所建立的 `Node` 的引用。 `NodeRef` 中的 `Node` 指的是 [`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html)。 `NodeRef::get` 方法將傳回一個 `Option<Node>` 值，但是，在 Yew 中，大多數情況下，您希望將此值轉換為特定元素，以便使用其特定方法。如果存在，可以使用 [`JsCast`](./wasm-bindgen.mdx#JsCast) 對 `Node` 值進行轉換，但是Yew 提供了 `NodeRef::cast` 方法來執行此轉換，以方便使用，因此您不一定需要為 `JsCast` 特性包含 `wasm-bindgen` 依賴項。\n\n下面的兩個程式碼區塊本質上是相同的，第一個使用 `NodeRef::cast`，第二個使用 [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) 在 `NodeRef::get` 傳回的 `web_sys::Node` 上。\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // 在這裡處理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // 在這裡處理 HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript 重構為 Rust 的範例\n\n這一節展示如何將與 Web API 互動的 JavaScript 程式碼範例重寫為 Rust 中的 `web-sys`。\n\n### JavaScript 範例\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e 為滑鼠事件對象\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left // 元素内的 x 位置。\n    var y = e.clientY - rect.top // 元素内的 y 位置。\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### 用 `web-sys` 重寫的範例\n\n只使用 `web-sys`，上面的 JavaScript 範例可以這樣實作：\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# 需要啟用所有我們想要使用的 web-sys 功能！\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// 我們現在需要保存 `mousemove` 閉包，以便在事件觸發時閉包仍然在記憶體中。\n```\n\n這個版本更加冗長，但你可能會注意到其中的一部分是由於失敗類型提醒我們，一些函數呼叫有必須保持的不變量，否則將在 Rust 中引發 panic。另一個冗長的部分是呼叫 `JsCast` 來將不同類型轉換為特定類型，以便呼叫其特定方法。\n\n### 用 Yew 重寫的範例\n\n在Yew 中，您將主要建立 [`Callback`](concepts/function-components/callbacks.mdx) 以在 [`html!`](concepts/html/introduction.mdx) 巨集中使用，因此範例將使用這種方法，而不是完全複製上面的方法：\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# 我們需要啟用 `DomRect` 特性以使用 `get_bounding_client_rect` 方法。\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## 補充依賴庫\n\n`web-sys` 是 Web API 的原始綁定，囙此在 Rust 中會有一些痛苦，因為它並不是為 Rust 或甚至强類型系統設計的，這就是社區 crate 提供了對 `web-sys` 的抽象，以提供更符合 Rust 習慣的 API。\n\n_[補充依賴庫清單]（/community/external-libs）_\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/contexts.mdx",
    "content": "---\ntitle: '上下文 (Contexts)'\nsidebar_label: Contexts\ndescription: '使用上下文傳遞深度嵌套資料'\n---\n\n通常，資料是透過 props 從父元件傳遞到子元件。\n但是，如果必須透過中間的許多元件傳遞它們，或者如果應用程式中的許多元件需要相同的訊息，傳遞 props 可能會變得冗長和煩人。\n上下文解決了這個問題，允許父元件使資料可用於其下方樹中的任何元件，無論多深，而無需透過 props 傳遞它們。\n\n## 使用 props 的問題：\"Prop Drilling\"\n\n傳遞 [props](./function-components/properties.mdx) 是從父元件直接傳遞資料到子元件的好方法。\n但是，當需要透過深層嵌套的組件樹傳遞資料或多個組件共享相同的資料時，傳遞 props 變得繁瑣。\n一種常見的資料共享解決方案是將資料提升到一個共同的祖先，並使子元件將其作為 props 接收。\n然而，這可能導致 props 必須通過多個元件才能到達需要它的元件。\n這種情況稱為 \"Prop Drilling\"。\n\n考慮以下範例，它透過 props 傳遞主題：\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App 根節點\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\n我們透過 `Navbar` 傳遞主題設定，以便它可以到達 `Title` 和 `NavButton`。\n如果 `Title` 和 `NavButton` 這些需要存取主題的元件可以直接存取主題而不必透過 prop 傳遞，那就更好了。\n上下文解決了這個問題，允許父元件將資料（在這種情況下是主題）傳遞給其子元件。\n\n## 使用上下文\n\n### 步驟 1：提供上下文\n\n需要一個上下文提供者來消費上下文。 `ContextProvider<T>`，其中 `T` 是用作提供者的上下文結構體。\n`T` 必須實作 `Clone` 和 `PartialEq`。 `ContextProvider` 是其子元件將擁有上下文的元件。\n當上下文變更時，子元件會重新渲染。一個結構體用來定義要傳遞的資料。 `ContextProvider` 可以這樣使用：\n\n```rust\nuse yew::prelude::*;\n\n/// App 主題\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// 主組件\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` 是 `Rc<UseStateHandle<Theme>>` 類型，而我們需要 `Theme`\n        // 所以我們對它進行解引用。\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // 這裡的每個子元件及其子元件都將存取此上下文。\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// 工具栏\n/// 此组件可以访问上下文。\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// 放置在 `Toolbar` 中的按鈕\n/// 由於此元件是元件樹中 `ThemeContextProvider` 的子元件，它也可以存取上下文。\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### 步驟 2：使用上下文\n\n#### 函數元件\n\n`use_context` 鉤子用於在函數元件中使用上下文。\n請參閱 [use_context 文件](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) 以了解更多資訊。\n\n#### 結構體組件\n\n我們有兩種選擇在結構體組件中使用上下文：\n\n- [高階元件](../advanced-topics/struct-components/hoc)：高階函數元件將使用上下文並將資料傳遞給需要它的結構體元件。\n- 直接在結構體組件中使用上下文。請參閱 [結構體組件作​​為消費者的範例](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## 使用場景\n\n通常，如果某些資料需要在樹的不同部分的遠端元件中使用，上下文可能會對你有所幫助。\n以下是一些這樣的例子：\n\n- **主題**：你可以在應用程式的頂部放置一個上下文來保存你的應用程式主題，並使用它來調整視覺外觀，如上例所示。\n- **目前使用者帳戶**：在許多情況下，元件需要知道目前登入的使用者。你可以使用上下文將目前使用者物件提供給元件。\n\n### 使用上下文前的考慮\n\n上下文非常容易使用，這也使得它們非常容易被誤用/過度使用。\n僅僅因為你可以使用上下文將 props 共享給多個層級深的元件，並不意味著你應該這樣做。\n\n例如，你可以提取一個元件並將該元件作為子元件傳遞給另一個元件。例如，\n你可能有一個 `Layout` 元件，它將 `articles` 作為 prop 並傳遞給 `ArticleList` 元件。\n你應該重構 `Layout` 元件，使其接受子元件作為 props 並顯示 `<Layout> <ArticleList {articles} /> </Layout>`。\n\n## 修改子元件的上下文值\n\n由於 Rust 的所有權規則，上下文不能有一個可以被子元件呼叫的 `&mut self` 方法。\n要修改上下文的值，我們必須將其與 reducer 結合使用。這可以透過使用\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) 鉤子完成。\n\n[上下文範例](https://github.com/yewstack/yew/tree/master/examples/contexts) 示範了使用上下文的可變上下文\n\n## 進一步閱讀\n\n- [上下文範例](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: '回调 (Callbacks)'\n---\n\n回調函數用於在元件樹中向上傳遞訊息，以及在事件處理期間與其他元件（如代理或 DOM）進行通訊。在內部，回調函數的類型只是一個 `Fn`，並且被包裝在 `Rc` 中，以便它們可以被廉價地複製。\n\n如果您想手動呼叫回調函數，可以使用 `emit` 函數。\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\"));  // 呼叫回調函數\n// web_sys::console::log_1(&result.into()); // 若取消註釋，將列印 \"Bye Bob\"\n```\n\n## 將回呼函數當作屬性傳遞\n\n在 yew 中的一個常見模式是建立一個回呼函數，並將其作為屬性傳遞給子元件。\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// 然後提供屬性 (Props)\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // 如果取消註釋，這裡會列印文本\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM 事件和回呼函數\n\n回調函數也用於連接到 DOM 事件。\n\n例如，這裡我們定義了一個回呼函數，當使用者點擊按鈕時將會呼叫：\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // 如果取消註釋，這裡會列印文本\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/children.mdx",
    "content": "---\ntitle: '子元素 (Children)'\n---\n\n`Children` 是一種特殊的屬性類型，可讓您接收嵌套的 `Html`，就像 html 子元素一樣提供。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // `children` 鍵很重要！\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n            // highlight-next-line\n            { props.children.clone() } // 可以靠這種方式轉送子元素\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/communication.mdx",
    "content": "---\ntitle: '組件之間的通訊'\n---\n\n## 父元件向子元件發送訊息\n\n將資料作為 [props](./properties) 傳遞，這會導致重新渲染，這是向子元件傳遞訊息的方法。\n\n## 子元件向父元件發送訊息\n\n透過 props 傳遞一個回調，子元件在事件上可以呼叫。 [範例](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/generics.mdx",
    "content": "---\ntitle: '泛型元件'\ndescription: '函數元件的 #[component] 屬性'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`#[component]` 屬性也適用於用於建立泛型元件的泛型函數。\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// 之後可以這樣使用\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// 或者\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: '自訂 Hooks'\n---\n\n## 定義自訂 Hooks\n\n元件的有狀態邏輯可以透過建立自訂 Hooks 來提取為可重複使用的函數。\n\n假設我們希望建立一個事件監聽器，監聽 `window` 物件上的事件。\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\n這段程式碼有一個問題：邏輯無法被另一個元件重複使用。如果我們建立另一個監聽不同事件的元件，而不是複製程式碼，我們可以將邏輯移入自訂 hook。\n\n我們將首先建立一個名為 `use_event` 的新函數。 `use_` 前綴表示函數是一個 hook。此函數將接受一個事件目標、一個事件類型和一個回呼。所有 hook 必須在其函數定義上標記為 `#[hook]`。\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\n這個簡單的 hook 可以透過組合內建 hook 來創建。在本例中，我們將使用 `use_effect_with` hook，因此當 hook 參數變更時，可以重新建立事件監聽器。\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\n儘管這種方法在幾乎所有情況下都有效，但它無法用於編寫像我們已經使用的預定義 hook 那樣的基本 hook。\n\n查看 [docs.rs](https://docs.rs/yew) 上的文件以及 `hooks` 目錄，查看預先定義 hook 的實作。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks 是一類能夠儲存狀態和執行副作用的函數。\n\nYew 提供了一些預先定義的 hooks。您也可以創建自己的 hooks，或發現許多[社區製作的 hooks](/community/awesome#hooks)。\n\n## Hooks 規則\n\n1. 每個 Hook 函數的名稱必須以 `use_` 開頭\n2. Hooks 只能在下列位置使用：\n\n- 函數/ Hook 的頂層\n- 函數/ Hook 內的區塊，只要它沒有被分支\n- 函數/ Hook 內頂層 `if` 表達式的條件\n- 函數/ Hook 內頂層 `match` 表達式的選擇器\n\n3. 每次渲染時，Hooks 必須以相同的順序呼叫。只有在使用 [Suspense](../../suspense.mdx) 時才允許提前返回\n\n這些規則由編譯時或執行時錯誤來執行。\n\n### 預定義 Hooks\n\nYew 提供了以下預定義 Hooks：\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\n這些 hooks 的文檔可以在 [Yew API 文件](https://yew-rs-api.web.app/next/yew/functional/)中找到。\n\n### 自訂 Hooks\n\n有些情況下，您可能想要定義自己的 Hooks，以將元件中的可能具有狀態的邏輯封裝到可重複使用的函數中。\n\n## 進一步閱讀\n\n- React 文件中有一個關於 [React hooks](https://reactjs.org/docs/hooks-intro.html) 的部分。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: '函數組件'\nslug: /concepts/function-components\n---\n\n讓我們重新回顧一下之前的標語：\n\n> Yew 的核心思想是將可重複使用的 UI 部分所需的所有內容集中在一個地方 - Rust 檔案中。\n\n我們將透過引入將定義應用程式的邏輯和呈現行為的概念來完善這個陳述：\"元件\"。\n\n## 什麼是元件？\n\n組件是 Yew 的構建塊。\n\n它們應當：\n\n- 以 [Props](./properties.mdx) 的形式接受參數\n- 可以擁有自己的狀態\n- 計算使用者可見的 HTML 片段（DOM）\n\n## Yew 組件的兩種風味\n\n您目前正在閱讀有關函數元件的內容 - 這是在開始使用 Yew 時以及在編寫簡單的呈現邏輯時編寫元件的建議方式。\n\n還有一種更高級但不太容易訪問的編寫組件的方式 - [結構組件](advanced-topics/struct-components/introduction.mdx)。它們允許非常詳細的控制，儘管大多數情況下您不需要那麼詳細的控制。\n\n## 建立函數元件\n\n若要建立函數元件，請將 `#[component]` 屬性加入到一個函式中。依照慣例，函數的名稱採用 PascalCase，與 `html!` 巨集中的普通 html 元素形成對比。\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 然後在其他地方，您可以在 `html!` 中使用元件\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## 組件內部發生了什麼\n\n在渲染時，Yew 將建立這些元件的虛擬樹。它將調用每個（函數）元件的 view 函數來計算 DOM 的虛擬版本（VDOM），您作為庫用戶將其視為 `Html` 類型。對於上面的範例，這將如下所示：\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\n當需要更新時，Yew 將再次呼叫 view 函數，並將新的虛擬 DOM 與其先前的版本進行協調，並僅將新的/更改的/必要的部分傳 播到實際的 DOM。這就是我們所說的 **渲染**。\n\n:::note\n\n實際上，`Html` 只是 `VNode` 的別名 - 一個虛擬節點。\n\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: '節點引用'\ndescription: 'DOM 外部存取'\n---\n\n`ref` 屬性可以用於將 `NodeRef` 附加到 HTML 元素上。在回呼中，您可以取得 `ref` 附加到的 DOM `Element`。這可以用於在 `view` 生命週期方法之外對 DOM 進行更改，檢索 `<input>` 的值以及透過 javascript API 直接與 DOM 互動。\n\n這對於獲取 canvas 元素或滾動到頁面的不同部分很有用。\n\n:::caution\n不要手動修改 Yew 渲染的 DOM 樹。如果不確定，請將 `NodeRef` 視為唯讀存取。\n:::\n\n## 進一步閱讀\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` 範例](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/properties.mdx",
    "content": "---\ntitle: '屬性 (Properties)'\ndescription: '父子元件通訊'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\n屬性 (Properties) 通常被簡寫為 \"Props\"。\n\n:::\n\n屬性 (Properties) 是元件的參數，Yew 可以監視這些參數。\n\n在元件的屬性中使用一個類型之前，它必須實作 `Properties` trait。\n\n## 響應性\n\n在重新渲染時，Yew 在協調虛擬 DOM 時檢查屬性是否已更改，以了解是否需要重新渲染巢狀元件。這樣，Yew 可以被認為是一個非常具有響應性的框架，因為來自父組件的變更總是會向下傳播，視圖永遠不會與來自屬性/狀態的資料不同步。\n\n:::tip\n\n如果您尚未完成 [教學](../../tutorial)，請嘗試並自行測試這種回應性！\n\n:::\n\n## 派生宏\n\nYew 提供了一個衍生宏，可以輕鬆地在結構體上實作 `Properties` trait。\n\n您衍生 `Properties` 的型別也必須實作 `PartialEq`，以便 Yew 可以進行資料比較。\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## 在函數元件中使用\n\n屬性 `#[component]` 允許在函式參數中選擇性地接收 Props。要提供它們，可以透過 `html!` 巨集中的屬性進行賦值。\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// 然後提供屬性\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// 沒有屬性需要提供\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## 派生巨集欄位屬性\n\n在派生 `Properties` 時，預設情況下所有欄位都是必要的。\n\n以下屬性可讓您為屬性提供預設值，當父元件沒有設定它們時將使用這些預設值。\n\n:::tip\n屬性在 Rustdoc 產生的文檔中是不可見的。您的屬性的文檔字串應該提到一個屬性是否是可選的，以及它是否有一個特殊的預設值。\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\n使用 `Default` trait 的欄位類型的預設值初始化屬性值。\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// 這樣使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\n使用 `value` 來初始化屬性值。 `value` 可以是傳回欄位類型的任何表達式。\n\n例如，要將布林屬性預設為 `true`，請使用屬性 `#[prop_or(true)]`。當屬性被建構時，表達式會被評估，且沒有給出明確的值。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// 這樣使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\n呼叫 `function` 來初始化屬性值。 `function` 應該有 `FnMut() -> T` 簽名，其中 `T` 是欄位類型。當沒有為該屬性給出明確的值時，將呼叫該函數。\n這個函數在屬性被建構時被呼叫。\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// 使用預設值\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// 或不覆蓋預設值\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## 使用 Properties 的效能開銷\n\n內部屬性是以引用計數的智慧型指標傳遞的。這意味著只有一個共享指標被傳遞到元件樹中的屬性，這樣就能節約克隆整個屬性的高昂成本。\n\n:::tip\n`AttrValue` 是我們用於屬性值的自訂類型，這樣就不用將它們定義為 String 或其他類似克隆成本高昂的類型了。\n:::\n\n## Props 巨集\n\n`yew::props!` 巨集允許您以與 `html!` 巨集相同的方式建立屬性。\n\n這個巨集使用與結構表達式相同的語法，只是您不能使用屬性或基本表達式 (`Foo { ..base }`)。類型路徑可以直接指向屬性 (`path::to::Props`)，也可以指向元件的關聯屬性 (`MyComp::Properties`)。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // 注意我們不需要指定 name 屬性\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## 自動產生屬性 (yew-autoprops)\n\n為了簡化您的開發流程，您也可以使用巨集 `#[autoprops]`（來自 `yew-autoprops` 套件）自動產生 `Properties` 結構體。\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// #[autoprops] 巨集必須出現在 #[component] 之前，順序很重要\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// 結構體 \"GreetingsProps\" 將會自動產生。\n//\n// `is_loading` 將作為值傳遞給元件，而 `message` 和 `name` 將使用引用，因為定義中有一個前導的 `&`。\n```\n\n## 評估順序\n\n屬性依照指定的順序進行評估，如下例所示：\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## 反模式\n\n雖然幾乎任何 Rust 類型都可以作為屬性傳遞，但有一些反模式應該避免。這些包括但不限於：\n\n1. 使用 `String` 類型而不是 `AttrValue`。 <br />\n   **為什麼不好？ ** `String` 克隆成本高。當屬性值與鉤子和回調一起使用時，通常需要克隆。 `AttrValue` 是一個引用計數的字串 (`Rc<str>`) 或一個 `&'static str`，因此非常便宜克隆。 <br />\n   **注意**：`AttrValue` 在內部是來自 [implicit-clone](https://crates.io/crates/implicit-clone) 的 `IString`。查看該包以了解更多資訊。\n2. 使用內部可變性。 <br />\n   **為什麼不好？ ** 內部可變性（例如 `RefCell`、`Mutex` 等）應該 _通常_ 避免使用。它可能會導致重新渲染問題（Yew 不知道狀態何時發生了變化），因此您可能需要手動強制重新渲染。就像所有事物一樣，它有其用武之地。請謹慎使用。\n3. 使用 `Vec<T>` 型別而不是 `IArray<T>`。 <br />\n   **為什麼不好？ ** `Vec<T>`，就像 `String` 一樣，克隆成本也很高。 `IArray<T>` 是一個引用計數的切片 (`Rc<[T]>`) 或一個 `&'static [T]`，因此非常便宜克隆。 <br />\n   **注意**：`IArray` 可以從 [implicit-clone](https://crates.io/crates/implicit-clone) 匯入。查看該包以了解更多資訊。\n4. 您發覺可能的新內容。您是否遇到了一個希望早點了解清楚的邊緣情況？請隨時建立一個問題或向本文檔提供修復的 PR。\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) 是一個實驗性包，可讓您根據函數的參數動態建立 Props 結構體。如果屬性結構體永遠不會被重複使用，這可能會很有用。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: '純組件'\n---\n\n每個函數元件都是一個[純](https://zh.wikipedia.org/zh-hk/%E7%BA%AF%E5%87%BD%E6%95%B0)函數，它接受一個屬性物件並傳回一個`Html` 物件。純函數是指在給定相同輸入時，總是會傳回相同輸出的函數。\n\n這個例子是一個純組件。對於給定的屬性 `is_loading`，它總是傳回相同的 `Html`，沒有任何副作用。\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\n如果您有一個內部純元件，它不使用 hooks 和其他元件機制，您通常可以將其編寫為傳回 `Html` 的普通函數，從而避免 Yew 運行元件生命週期相關的一些開銷。使用 [表達式語法](concepts/html/literals-and-expressions.mdx#expressions) 在 `html!` 中渲染它們。\n:::\n\n## 非純組件\n\n您可能想知道，如果元件不使用任何全域變量，那麼它是否可以是不“純”的，因為它只是在每次渲染時調用的固定函數。\n這就是下一個主題 - [hooks](./hooks) 的用武之地。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/function-components/state.mdx",
    "content": "---\ntitle: '狀態'\n---\n\n## 如何儲存狀態的一般視圖\n\n這個表格可以作為一個指南，幫助您決定哪種狀態儲存類型最適合您的用例：\n\n| Hook             | 類型                       | 何時渲染?                        | 作用域                   |\n| ---------------- | -------------------------- | -------------------------------- | ------------------------ |\n| [use_state]      | `T`                        | 被設定一個值                     | 組件內部實例             |\n| [use_state_eq]   | `T: PartialEq`             | 被設定一個不同的值               | 組件內部實例             |\n| [use_reducer]    | `T: Reducible`             | 被呼叫歸納                       | 組件內部實例             |\n| [use_reducer_eq] | `T: Reducible + PartialEq` | 被呼叫歸納，歸納後的值與之前不同 | 組件內部實例             |\n| [use_memo]       | `Deps -> T`                | 依賴項發生變化                   | 組件內部實例             |\n| [use_callback]   | `Deps -> Callback<E>`      | 依賴項發生變化                   | 組件內部實例             |\n| [use_mut_ref]    | `T`                        | -                                | 組件內部實例             |\n| 全域靜態常數     | `T`                        | -                                | 全域，任何位置都可以使用 |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/classes.mdx",
    "content": "---\ntitle: '類別'\ndescription: '一個方便的巨集來處理類別'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 類別\n\n`Classes` 結構體可以用來處理 HTML 類別。\n\n將字串推送到集合時，`Classes` 確保每個類別都有一個元素，即使單一字串可能包含多個類別。\n\n`Classes` 也可以透過使用 `Extend`（即 `classes1.extend(classes2)`）或 `push()`（即 `classes1.push(classes2)`）來合併。任何實作 `Into<Classes>` 的類型都可以推送到現有的 `Classes` 上。\n\n`classes!` 是一個方便的巨集，它建立一個單一的 `Classes`。它的輸入接受一個逗號分隔的表達式清單。唯一的要求是每個表達式都實作了 `Into<Classes>`。\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 接受類別的元件\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/components.mdx",
    "content": "---\ntitle: '組件'\ndescription: '使用元件層次結構建立複雜的佈局'\n---\n\n## 基礎\n\n元件可以在 `html!` 巨集中使用：\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // 沒有屬性\n        <MyComponent />\n\n        // 使用屬性\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // 一次提供所有屬性\n        <MyComponentWithProps ..props.clone() />\n\n        // 使用變數中的屬性，並覆寫特定值\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## 嵌套\n\n如果組件在其 `Properties` 中有一個 `children` 字段，它可以接受子組件/元素\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\n`html!` 巨集允許您使用`..props` 語法傳遞一個基本表達式，而不是單獨指定每個屬性，類似於Rust 的[函數式更新語法](https://doc.rust-lang.org /stable/reference/expressions/struct-expr.html#functional-update-syntax)。\n這個基本表達式必須出現在傳遞任何單獨的 props 之後。\n當傳遞一個帶有 `children` 欄位的基本 props 表達式時，`html!` 巨集中傳遞的子元素將覆蓋已經存在於 props 中的子元素。\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // 子元素將覆蓋 props.children\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## 相關範例\n\n- [函數化 Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [函數化路由](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: '條件渲染'\ndescription: '在 html 中有條件地渲染節點！ '\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If 區塊\n\n要有條件地渲染一些標記，我們將其包裝在 `if` 區塊中：\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/elements.mdx",
    "content": "---\ntitle: '元素'\ndescription: '支援 HTML 和 SVG 元素'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM 節點\n\n在 Yew 中手動建立或管理 DOM 節點的原因有很多，例如與可能與受管理元件衝突的 JS 庫整合。\n\n使用 `web-sys`，您可以建立 DOM 元素並將其轉換為 `Node` - 然後可以使用 `VRef` 將其用作 `Html` 值：\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // 帶記憶能力的函數，只會執行一次\n    let node = use_memo(\n        (),\n        |_| {\n            // 從文件中建立一個 div 元素\n            let div: Element = document().create_element(\"div\").unwrap();\n            // 新增內容、類別等\n            div.set_inner_html(\"Hello, World!\");\n            // 將 Element 轉換為 Node\n            let node: Node = div.into();\n            // 將該 Node 作為 Html 值傳回\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo 回傳的是 Rc 指針，所以我們需要解引用和克隆\n    (*node).clone()\n}\n\n```\n\n## 動態標籤名\n\n在建立高階元件時，您可能會發現自己處於一個標籤名不是靜態的情況。例如，您可能有一個 `Title` 元件，根據等級屬性可以渲染從 `h1` 到 `h6` 的任何內容。而不是使用一個大的匹配表達式，Yew 允許您動態設定標籤名，使用 `@{name}`，其中 `name` 可以是傳回字串的任何表達式。\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## 邏輯值屬性\n\n一些內容屬性（例如 checked、hidden、required）被稱為邏輯值屬性。在 Yew 中，邏輯值屬性需要設定為布林值：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\n這與以下的 **HTML** 功能上是等價的：\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\n將邏輯值屬性設為 false 等效於不使用該屬性；可以使用邏輯表達式的值：\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\n這與以下 **HTML** 結果等價：\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## 類似字串的屬性\n\n除了一些邏輯值屬性，您可能會處理許多類似字串的 HTML 屬性，Yew 有幾種選項可以將類似字串的值傳遞給元件。\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\n它們都是有效的，**但**我們鼓勵您更傾向於使用 Yew 的自訂 `AttrValue`，特別是如果您需要複製或將它們作為屬性傳遞給另一個元件。\n\n## HTML 元素的可選屬性\n\n大多數 HTML 屬性可以使用可選值（Some(x) 或 None）。這使我們可以在屬性被標記為可選時省略該屬性。\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\n如果屬性設為 `None`，則該屬性將不會在 DOM 中設定。\n\n## 相關範例\n\n- [內嵌 HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/events.mdx",
    "content": "---\ntitle: '事件'\n---\n\n## 介紹\n\nYew 與 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate 集成，並使用該 crate 中的事件。下面的[表格](#event-types)列出了在 `html!` 巨集中接受的所有 `web-sys` 事件。\n\n您仍然可以為下表中未列出的事件新增 [`Callback`](../function-components/callbacks.mdx)，請參閱[手動事件監聽器](#manual-event-listener)。\n\n## 事件類型\n\n:::tip\n所有的事件類型都在 `yew::events` 下重新匯出。\n使用 `yew::events` 中的類型比手動將 `web-sys` 作為依賴項包含在您的 crate 中更容易確保版本相容性，\n因為您不會使用與 Yew 指定的版本衝突的版本。\n:::\n\n事件監聽器的名稱是在 `html` 巨集中新增事件 `Callback` 時預期的名稱：\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\n事件名稱是監聽器名稱去掉 \"on\" 前綴，因此 `onclick` 事件監聽器監聽 `click` 事件。查看本頁末的[完整事件清單](#available-events)及其類型。\n\n## 事件捕獲 {#event-bubbling}\n\nYew 調度的事件遵循虛擬 DOM 層次結構，向上冒泡到監聽器。目前，僅支援監聽器的冒泡階段。請注意，虛擬 DOM 層次結構通常（但並非總是）與實際 DOM 層次結構相同。在處理[傳送門](../../advanced-topics/portals)和其他更高級技術時，這一區別很重要。對於良好實現的元件，直覺應該是事件從子元件冒泡到父元件。這樣，您在 `html!` 中所寫的層次結構就是事件處理程序觀察到的層次結構。\n\n如果您不想要事件冒泡，可以透過呼叫\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n在啟動應用程式*之前*。這會加快事件處理速度，但某些元件可能會因未收到預期的事件而中斷。請謹慎使用！\n\n## 事件委託\n\n可能會讓人驚訝的是，事件監聽器並不是直接註冊在它們被渲染的元素上。相反，事件是從 Yew 應用的子樹根節點委託的。不過，事件仍然以其原生形式傳遞，並且不會創建任何合成形式。這可能會導致 HTML 監聽器中預期的事件與 Yew 中出現的事件之間的不符。\n\n- [`Event::current_target`] 指向 Yew 子樹根節點，而不是新增監聽器的元素。如果您想存取底層的 `HtmlElement`，請使用 [`NodeRef`](../function-components/node-refs.mdx)。\n- [`Event::event_phase`] 總是 [`Event::CAPTURING_PHASE`]。在內部，事件將表現得像是在冒泡階段，事件傳播將被重播，並且事件會[向上冒泡](#event-bubbling)，即虛擬DOM 中較高的事件監聽器將在較低的事件監聽器之後觸發。目前，Yew 不支援捕獲監聽器。\n\n這也意味著由 Yew 註冊的事件通常會在其他事件監聽器之前觸發。\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## 具備類型的事件目標\n\n:::caution\n在本節中，**target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))** 總是指的是事件從其派發的元素。\n\n這**不一定**總是指 `Callback` 所放置的元素。\n:::\n\n在事件 `Callback` 中，您可能想要取得該事件的目標。例如，`change` 事件沒有提供任何訊息，但用於通知某些內容已更改。\n\n在 Yew 中，以正確的類型獲取目標元素可以透過幾種方式完成，我們將在這裡逐一介紹。呼叫事件上的[`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) 傳回一個可選的[ `web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html) 類型，當您想知道輸入元素的值時，這可能看起來不太有用。\n\n在下面的所有方法中，我們將解決相同的問題，以便清楚地了解方法的不同之處，而不是手邊的問題。\n\n**問題：**\n\n我們在 `<input>` 元素上有一個 `onchange` `Callback`，每次呼叫時，我們希望向元件發送一個[更新](components#update) `Msg`。\n\n我們的 `Msg` 列舉如下：\n\n```rust\npub enum Msg {\n InputValue(String),\n}\n```\n\n### 使用 `JsCast`\n\n[`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate 有一個有用的trait：[`JsCast`](https://rustwasm.github .io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)，它允許我們在類型之間直接轉換，只要它實現了`JsCast` 就行。我們可以謹慎地轉換，這涉及運行時檢查和處理 `Option` 和 `Result` 的邏輯，或者我們也可以冒險直接強行轉換。\n\n多說無益，看代碼：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# 需要 wasm-bindgen 用於呼叫 JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // 當事件被建立時，目標是未定義的，只有在派發時才會新增目標。\n            let target: Option<EventTarget> = e.target();\n            // 事件可能會冒泡，因此此偵聽器可能會捕獲不是 HtmlInputElement 類型的子元素的事件。\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // 你必須了解 target 是 HtmlInputElement，否則呼叫 value 將是未定義行為（UB）。\n        // 在這裡，我們確信這是輸入元素，因此我們可以在不檢查的情況下將其轉換為適當的類型。\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n`JsCast` 提供的方法是 [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\n和 [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)。\n如你所見，它們允許我們從 `EventTarget` 轉換為 [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html)。\n`dyn_into` 方法是謹慎的，因為它會在運行時檢查類型是否實際為 `HtmlInputElement`，如果不是則返回\n`Err(JsValue)`。 [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n是一個通用類型，將原來的物件回傳給你，以便再次嘗試轉換為別的類型。\n\n這會兒你可能會想，什麼時候可以使用危險版本？在上面的情況下，它是安全的<sup>1</sup>，因為我們將 `Callback` 設定在一個沒有子元素的元素上，所以目標只能是同一個元素。\n\n_<sup>1</sup> 只要牽涉到 JS 領域，就是安全的。 _\n\n### 使用 `TargetCast`\n\n**強烈建議先閱讀 [使用 JsCast](#using-jscast)！ **\n\n:::note\n`TargetCast` 的設計目的是讓新用戶了解 `JsCast` 的行為，但範圍更小，僅涉及事件及其目標。\n\n選用 `TargetCast` 或 `JsCast` 純粹是個人偏好，實際您會發現 `TargetCast` 的實作和 `JsCast` 的功能很相似。\n:::\n\n`TargetCast` trait 是在 `JsCast` 基礎之上建構的，專門用於從事件中取得類型化的事件目標。\n\n`TargetCast` 是 Yew 的一部分，因此無需添加依賴項即可在事件上使用 trait 方法，但它的工作方式與 `JsCast` 非常相似。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // 你必須清楚 target 是 HtmlInputElement，否則呼叫 value 將是未定義行為（UB）。\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n如果您已經了解了 `JsCast`，或者了解了這個 trait，您可能會發現 `TargetCast::target_dyn_into` 與 `JsCast::dyn_into` 相似，但專門用於事件的目標。 `TargetCast::target_unchecked_into` 與 `JsCast::unchecked_into` 類似，因此上面關於 `JsCast` 的所有警告都適用於 `TargetCast`。\n\n### 使用 `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) 可以取代查詢給定給 `Callback` 的事件。\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\n透過 `NodeRef`，你可以忽略事件並使用 `NodeRef::cast` 方法取得一個`Option<HtmlInputElement>` - 這是可選的，因為在設定 `NodeRef` 之前呼叫 `cast`，或者當類型不符時將會回傳 `None`。\n\n你可能會看到，透過使用 `NodeRef`，我們不必將 `String` 傳回狀態，因為我們總是存取 `input_node_ref` - 因此我們可以這樣做：\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // 對 value 做點什麼\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\n您選擇哪種方法取決於您的元件和您的偏好，沒有所謂的*推薦*方法。\n\n## 手動事件監聽器\n\n您可能想要監聽 Yew 的 `html` 巨集不支援的事件，請查看[這裡列出的支援的事件](#event-types)。\n\n為了手動為某個元素新增事件監聽器，我們需要藉助 [`NodeRef`](../function-components/node-refs.mdx)，以便在 `use_effect_with` 中使用 [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) 和 [wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API 新增監聽器。\n\n以下範例將展示如何為虛構的 `custard` 事件新增監聽器。所有不受 yew 支援的事件或自訂事件都可以表示為\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html)。如果您需要存取自訂/不受支援事件的特定方法或字段，可以使用\n[`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) 的方法將其轉換為所需的類型。\n\n### 使用 `Closure`（冗長版本）\n\n直接使用 `web-sys` 和 `wasm-bindgen` 的介面可能有點痛苦…所以要有點心理準備（[感謝 `gloo`，有了更簡潔的方法](#using-gloo-concise)）。\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 建立您通常會建立的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 對 custard 做點什麼..\n                    });\n\n                    // 從 Box<dyn Fn> 創建一個 Closure - 這必須是 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有關 `Closure` 的更多信息，請參見 [wasm-bindgen 指南](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html)。\n\n### 使用 `gloo`（簡潔版本）\n\n更方便的方法是使用 `gloo`，更具體地說是 [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)，\n它是 `web-sys`、`wasm-bindgen` 的高層抽象實作。\n\n`gloo_events` 提供了 `EventListener` 類型，可以用來建立和儲存事件監聽器。\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // 建立您通常會建立的 Callback\n                    let oncustard = Callback::from(move |_: Event| {\n                        // 對 custard 做點什麼..\n                    });\n\n                    // 從 Box<dyn Fn> 創建一個 Closure - 這必須是 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\n有關 `EventListener` 的更多信息，請參見 [gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html)。\n\n## 可用事件的完整清單 {#available-events}\n\n| 偵聽器名稱                  | `web_sys` 事件類型                                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/fragments.mdx",
    "content": "---\ntitle: '空標籤 (Fragments)'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 巨集總是需要一個根節點。為了繞過這個限制，您可以使用一個“空標籤”（也稱為“fragments”）。\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// 錯誤：只允許一個根 HTML 元素\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: '用於產生 HTML 和 SVG 的過程巨集'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`html!` 巨集可讓您聲明性地編寫 HTML 和 SVG 程式碼。它類似於 JSX（一種允許您在 JavaScript 中編寫類似 HTML 的程式碼的擴充）。\n\n**重要提示**\n\n1. `html! {}` 巨集只能接受一個根HTML 節點（您可以透過使用[fragments](./fragments.mdx) 或[iterators](./../html/lists.mdx) 來規避這一點）\n2. 空的 `html! {}` 呼叫是有效的，不會渲染任何內容\n3. 字面量必須永遠用引號引起來並用大括號括起來：`html! { <p>{ \"Hello, World\" }</p> }`\n4. `html!` 巨集會將所有標籤名稱轉換為小寫。若要使用大寫字元（某些SVG 元素所需的字元）請使用[動態標籤名稱](concepts/html/elements.mdx#dynamic-tag-names)：`html! { <@{\"myTag\"}>< /@> }`\n\n:::note\n`html!` 巨集可能會達到編譯器的預設遞歸限制。如果遇到編譯錯誤，請在 crate 根目錄中新增類似 `#![recursion_limit=\"1024\"]` 的屬性以解決問題。\n:::\n\n## 標籤 (Tags) 結構\n\n標籤 (Tags) 是基於 HTML 標籤。元件、元素和清單都基於此標籤語法。\n\n標籤必須或自閉合 `<... />`，或對於每個開始標籤都有一個對應的結束標籤。\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- 缺少閉合標籤\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- 缺少閉合標籤\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\n方便起見，通常需要閉合標籤的元素**允許**自閉合。例如，編寫 `html! { <div class=\"placeholder\" /> }` 是有效的。\n:::\n\n建立複雜的巢狀 HTML 和 SVG 佈局還是很容易的：\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\n如果您使用 Rust 編譯器的開發者版本編譯 Yew，巨集將警告您可能遇到的一些常見陷阱。當然，您可能需要使用穩定版編譯器（例如，您的組織可能有政策要求這樣做）進行發布構建，但即使您使用的是穩定工具鏈，運行`cargo +nightly check` 也可能會標記一些可以改進HTML 程式碼的方法。\n\n目前，這些 lint 主要與可訪問性相關。如果您有 lint 的想法，請隨時[在此問題中發表意見](https://github.com/yewstack/yew/issues/1334)。\n\n## 指定屬性和屬性\n\n屬性與普通 HTML 中的元素設定方式相同：\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\n屬性在元素名稱之前用 `~` 指定：\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\n如果值是一個字面量的話，圍繞值的大括號可以省略。\n\n:::\n\n:::note 什麼是字面量\n\n字面量是 Rust 中所有有效的[字面量表達式](https://doc.rust-lang.org/reference/expressions/literal-expr.html)。請注意，[負數**不是**字面量](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)，因此必須用大括號括起來 `{-6}`。\n\n:::\n\n:::note 元件屬性\n元件屬性以 Rust 物件傳遞，與此處所述的元素參數 (Attributes) / 屬性 (Properties) 不同。\n在[元件屬性](../function-components/properties.mdx)中了解更多。\n:::\n\n### 特殊屬性\n\n有一些特殊屬性不會直接影響 DOM，而是作為 Yew 虛擬 DOM 的指令。目前有兩個這樣的特殊屬性：`ref` 和 `key`。\n\n`ref` 可讓您直接存取和操作底層 DOM 節點。有關更多詳細信息，請參閱 [Refs](../function-components/node-refs.mdx)。\n\n另一方面，`key` 為元素提供了一個唯一標識符，Yew 可以用於最佳化目的。\n\n:::info\n[了解更多相關內容](./html/lists)\n:::\n\n## 條件渲染\n\n可以透過使用 Rust 的條件結構來條件性地渲染標記。目前只支援 `if` 和 `if let`。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\n閱讀[條件渲染](./conditional-rendering.mdx)一節以了解更多\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/lists.mdx",
    "content": "---\ntitle: '列表'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## 迭代器\n\n從迭代器建立 HTML 有 3 種方法：\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` 迴圈\">\n主要方法是使用 for 迴圈，與 Rust 中已有的 for 迴圈相同，但有 2 個關鍵區別：\n1. 與標準 for 迴圈不能傳回任何內容不同，`html!` 中的 for 迴圈會被轉換為節點清單；\n2. 發散運算式，即 `break`、`continue` 在 `html!` 中的 for 迴圈主體內是不允許的。\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` 區塊\">\n另一種方法是使用 `for` 關鍵字，這不是原生的 Rust 語法，而是由 HTML 巨集用於輸出顯示迭代器所需的程式碼。\n當迭代器已經計算好，只需要將其傳遞給巨集時，這種方法比第一種更好。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` 方法\">\n\n最後一種方法是在迭代器的最終轉換上呼叫 `collect::<Html>()`，它傳回一個 Yew 可以顯示的清單。\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## 鍵 (Key) 列表\n\n鍵 (Key) 列表是一個最佳化的列表，其中**所有**子元素都有鍵。\n`key` 是 Yew 提供的一個特殊屬性，它為 HTML 元素或元件提供一個唯一標識符，用於 Yew 內部的最佳化。\n\n:::caution\nKey 只需要在每個清單中是唯一的，與 HTML `id` 的全域唯一性相反。它不應該依賴於列表的順序。\n:::\n\n始終建議為清單新增按鍵 (key)。\n\n可以透過將唯一的 `String`、`str` 或整數傳遞給特殊的 `key` 屬性來新增鍵：\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### 效能優化\n\n我們有一個[帶有鍵 (keys) 的列表範例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)可以讓你測試效能上的改進，這裡有一個簡單的測試流程：\n\n1. 進入[線上示範](https://examples.yew.rs/keyed_list)\n2. 新增 500 個元素\n3. 停用鍵\n4. 反轉列表\n5. 看 \"最後一次渲染花費了 Xms\"（在撰寫本文時，大約為 60ms）\n6. 啟用鍵\n7. 再次反轉列表\n8. 看 \"最後一次渲染花費了 Xms\"（在撰寫本文時，大約為 30ms）\n\n截至撰寫本文時，對於 500 個組件，速度提高了 2 倍。\n\n### 原理解釋\n\n通常，當你迭代時，只需要在每個列表項目上添加一個鍵，資料的順序可能會改變。\n在重新渲染清單時，它用於加速協調過程。\n\n如果沒有鍵，假設你迭代 `[\"bob\", \"sam\", \"rob\"]`，最終得到的 HTML 如下：\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\n然後在下一次渲染時，如果你的清單更改為 `[\"bob\", \"rob\"]`，Yew 可以刪除 id=\"rob\" 的元素，並將 id=\"sam\" 更新為 id=\"rob\"。\n\n如果你為每個元素添加了一個鍵，初始HTML 將保持不變，但在使用修改後的列表`[\"bob\", \"rob\"]` 進行渲染後，Yew 只會刪除第二個HTML 元素，而其他元素則保持不變，因為它可以使用鍵將它們關聯起來。\n\n如果你遇到了一個從一個元件切換到另一個元件的 bug/\"feature\"，但兩者都有一個 div 作為最高渲染元素。\nYew 在這些情況下會重複使用已渲染的 HTML div 作為最佳化。\n如果你需要該 div 被重新建立而不是被重複使用，那麼你可以添加不同的鍵，它們將不會被重複使用。\n\n## 進一步閱讀\n\n- [TodoMVC 範例](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [帶有按鍵 (keys) 的清單範例](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [路由範例](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: '字面量與表達式'\n---\n\n## 字面量\n\n如果表達式解析為實現了 `Display` 的類型，它們將被轉換為字串並插入到DOM 中作為[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 節點。\n\n:::note\n字串字面量會建立 `Text` 節點，瀏覽器將其視為字串。因此，即使表達式包含 `<script>` 標籤，您也不會遇到 XSS 等安全性問題，除非您將表達式包裝在 `<script>` 區塊中。\n:::\n\n所有顯示文字都必須用 `{}` 區塊括起來，因為文字被視為表達式。這是 Yew 與普通 HTML 語法最大的偏差。\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## 表達式\n\n您可以使用 `{}` 區塊在 HTML 中插入表達式，只要它們解析為 `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\n通常將這些表達式提取到函數或閉包中以優化可讀性是有意義的：\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/router.mdx",
    "content": "---\ntitle: '路由 (Router)'\ndescription: 'Yew 的官方路由庫'\n---\n\n單頁應用程式 (SPA) 中的路由器處理根據 URL 顯示不同的頁面。與點擊連結時請求不同的遠端資源的預設行為不同，路由器會在本機設定 URL 以指向應用程式中的有效路由。然後，路由器偵測到此變更並決定要渲染的內容。\n\nYew 在 `yew-router` crate 中提供了路由器支援。要開始使用它，請將依賴項新增至您的 `Cargo.toml` 檔案中。\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\n所需的工具均在 `yew_router::prelude` 模組中提供，\n\n## 用法\n\n最開始，你需要定義一個 `Route`。\n\n路由由一個 `enum` 定義，它衍生自 `Routable`。這個枚舉必須實作 `Clone + PartialEq`。\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\n`Route` 與 `<Switch />` 元件配對，後者會找到與瀏覽器目前 URL 相符的路徑變體，並將其傳遞給 `render` 回呼。然後回調決定要渲染的內容。如果沒有路徑匹配，路由器會導航到帶有 `not_found` 屬性的路徑。如果沒有指定路由，則不會渲染任何內容，並且會在控制台中記錄一條訊息，說明沒有符合的路由。\n\nyew-router 的大多數元件，特別是 `<Link />` 和 `<Switch />`，必須是某個 Router 元件（例如 `<BrowserRouter />`）的（深層）子元素。通常在應用程式中只需要一個 Router，通常由最頂層的 `<App />` 元件立即渲染。 Router 註冊了一個上下文，這是 Links 和 Switches 功能所需的。下面提供了一個範例。\n\n:::caution\n在瀏覽器環境中使用 `yew-router` 時，強烈建議使用 `<BrowserRouter />`。您可以在 [API 參考](https://docs.rs/yew-router/) 中找到其他路由器類型。\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### 路徑段\n\n路由還可以使用動態和命名通配符段從路由中提取資訊。然後，您可以在 `<Switch />` 內存取貼文的 id，並透過屬性將其轉發到對應的元件。\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\n您也可以使用普通的 `Post` 變體，而不是 `Post {id: String}`。例如，當 `Post` 與另一個路由器一起渲染時，該欄位可能是多餘的，因為另一個路由器可以匹配並處理路徑。有關詳細信息，請參閱下面的[嵌套路由器](#nested-router)部分。\n:::\n\n請注意，欄位必須實作 `Clone + PartialEq` 作為 `Route` 枚舉的一部分。它們還必須實作 `std::fmt::Display` 和 `std::str::FromStr` 以進行序列化和反序列化。整數、浮點數和字串等原始類型已經滿足這些要求。\n\n當路徑的形式匹配，但反序列化失敗（根據 `FromStr`）。路由器將認為路由不匹配，並嘗試渲染未找到的路由（或者如果未指定未找到的路由，則渲染空白頁面）。\n\n參考以下範例：\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// 切換函數會渲染 News 和 id。這裡省略了。\n```\n\n當段超過 255 時，`u8::from_str()` 將失敗並傳回 `ParseIntError`，路由器將認為路由不符。\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\n有關路由語法和如何綁定參數的更多信息，請查看 [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params)。\n\n### 位置 (Location)\n\n路由器透過上下文提供了一個通用的 `Location` 結構，可以用來存取路由資訊。它們可以透過鉤子或 `ctx.link()` 上的便捷函數來檢索。\n\n### 導航\n\n`yew_router` 提供了一些工具來處理導航。\n\n#### 連結\n\n`<Link />` 渲染為`<a>` 元素，`onclick` 事件處理程序將呼叫 [preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)，並將目標頁面推送到歷史記錄中並渲染所需的頁面，這正是單頁應用程式所期望的行為。普通錨元素的預設 `onclick` 會重新載入頁面。\n\n`<Link />` 元件也會將其子元素傳遞給 `<a>` 元素。可以將其視為應用程式內路由的 `<a/>` 替代品。不同之處在於你需要提供 `to` 屬性而不是 `href`。範例用法如下：\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\n結構體變數也可以正常運作：\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### 導航接口\n\n導航器 API 為函數元件和結構元件提供。它們使回調能夠更改路由。可以在任一情況下取得 `Navigator` 實例以操作路由。\n\n##### 函數式元件\n\n對於函數元件，當底層導覽器提供者變更時，`use_navigator` 鉤子會重新渲染元件。\n以下是實現一個按鈕的範例，該按鈕在點擊時導航到 `Home` 路由。\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\n這裡的範例使用了 `Callback::from`。如果目標路由可以與元件所在的路由相同，或只是為了安全起見，請使用普通的回呼。例如，考慮在每個頁面上都有一個徽標按鈕，點擊該按鈕會返回主頁。在主頁上點擊該按鈕兩次會導致程式碼崩潰，因為第二次點擊會推送一個相同的 Home 路由，並且 `use_navigator` 鉤子不會觸發重新渲染。\n:::\n\n如果您想要取代目前的位置而不是將新位置推到堆疊上，請使用 `navigator.replace()` 而不是 `navigator.push()`。\n\n您可能會注意到 `navigator` 必須移動到回呼中，因此不能再次用於其他回呼。幸運的是，`navigator` 實作了 `Clone`，例如，以下是如何為不同的路由設定多個按鈕：\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### 結構體組件\n\n對於結構體元件，可以透過 `ctx.link().navigator()` API 取得 `Navigator` 實例。其餘部分與函數組件的情況相同。以下是一個渲染單一按鈕的視圖函數範例。\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### 重定向\n\n`yew-router` 在 prelude 中也提供了一個 `<Redirect />` 元件。它可以用於實現與導航器 API 類似的效果。該元件接受一個 `to` 屬性作為目標路由。當渲染 `<Redirect/>` 時，使用者將被重定向到屬性中指定的路由。以下是一個範例：\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // 建立對 `use_user` 的鉤子\n    let user = match use_user() {\n        Some(user) => user,\n        // 當使用者為 `None` 時重定向到登入頁面\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... 實際頁面內容\n}\n```\n\n:::tip 如何選擇 `Redirect` 或 `Navigator`\nNavigator API 是在回呼中操作路由的唯一方法。\n而 `<Redirect />` 可以作為元件中的回傳值使用。您可能還想在其他非元件上下文中使用 `<Redirect />`，例如在[嵌套路由器](#nested-router)的 switch 函數中。\n:::\n\n### 監聽變化\n\n#### 函數式元件\n\n您可以使用 `use_location` 和 `use_route` 鉤子。當提供的值發生變化時，您的元件將重新渲染。\n\n#### 結構體組件\n\n為了回應路由變化，您可以將回呼閉包傳遞給 `ctx.link()` 的 `add_location_listener()` 方法。\n\n:::note\n一旦位置監聽器被刪除，它將被取消註冊。請確保將句柄儲存在元件狀態中。\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // 處理事件\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` 和 `ctx.link().route::<R>()` 也可以用於一次性擷取位置和路由。\n\n### 查詢參數\n\n#### 在導航時指定查詢參數\n\n為了在導覽到新路由時指定查詢參數，可以使用 `navigator.push_with_query` 或 `navigator.replace_with_query` 函數。它使用 `serde` 將參數序列化為 URL 的查詢字串，因此任何實作了 `Serialize` 的類型都可以傳遞。最簡單的形式是包含字串對的 `HashMap`。\n\n#### 取得目前路由的查詢參數\n\n`location.query` 用來取得查詢參數。它使用 `serde` 從 URL 的查詢字串中反序列化參數。\n\n## 嵌套路由器\n\n當應用程式變得更大時，嵌套路由器可能會很有用。考慮以下路由器結構：\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\n嵌套的 `SettingsRouter` 處理所有以 `/settings` 開頭的 URL。此外，它會將未符合的 URL 重新導向到主 `NotFound` 路由。因此，`/settings/gibberish` 將會重新導向到 `/404`。\n\n:::caution\n\n請注意，該介面仍在開發中，這樣寫的方式尚未最終確定\n\n:::\n\n可以使用以下程式碼實作：\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### 基底路徑 (Basename)\n\n可以使用 `yew-router` 定義基底路徑 (Basename)。\n基底路徑是所有路由的公共前綴。導航器 API 和 `<Switch />` 元件都支援基底路徑設定。所有推送的路由都會加上基底路徑前綴，所有的 switch 都會在嘗試將路徑解析為 `Routable` 之前去掉基底路徑。\n\n如果沒有為 Router 元件提供基底路徑屬性，它將使用 HTML 檔案中 `<base />` 元素的 href 屬性，並在 HTML 檔案中沒有 `<base />` 元素時回退到 `/`。\n\n## 相關範例\n\n- [路由](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## 介面參考\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/concepts/suspense.mdx",
    "content": "---\ntitle: '佔位標籤 (Suspense)'\ndescription: '用於資料獲取的佔位標籤'\n---\n\n佔位標籤 (Suspense) 是一種在等待任務完成前暫停元件渲染的方式，同時顯示一個回退（佔位符）UI。\n\n它可以用於從伺服器取得數據，等待代理完成任務，或執行其他後台非同步任務。\n\n在佔位標籤出現之前，資料擷取通常發生在元件渲染之後（渲染時取得）或之前（取得後渲染）。\n\n### 邊渲染，邊下載\n\n佔位標籤 (Suspense) 提供了一種新的方法，允許元件在渲染過程中啟動資料請求。當元件啟動資料請求時，渲染過程將被暫停，並顯示一個回退 UI，直到請求完成。\n\n建議使用鉤子 (Hook) 來使用佔位標籤。\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n在上面的範例中，`use_user` 鉤子將在載入使用者資訊時暫停元件渲染，並在載入 `user` 之前顯示 `Loading...` 佔位符。\n\n要定義一個暫停元件渲染的鉤子，它需要傳回一個 `SuspensionResult<T>`。當元件需要暫停時，鉤子應該傳回一個 `Err(Suspension)`，使用者應該使用 `?` 解包它，這樣它將被轉換為 `Html`。\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 當使用者載入完成時，我們將其作為 Ok(user) 傳回。\n        Some(m) => Ok(m),\n        None => {\n            // 當使用者仍在載入時，我們建立一個 `Suspension`\n            // 並在資料載入完成時呼叫 `SuspensionHandle::resume`，\n            // 元件將自動重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### 關於實作暫停鉤子 (Hook) 的注意事項\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) 傳回 2 個值：暫停上下文本身和一個暫停句柄。後者負責在何時重新渲染暫停的元件，它提供了 2 種可互換的方法：\n\n1. 呼叫其 [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) 方法。\n2. 丟棄句柄。\n\n:::danger\n\n暫停句柄必須儲存直到更新元件的時候，也就是使用新接收的資料；否則，暫停的元件將進入無限重新渲染循環，從而影響效能。\n在上面的範例中，暫停句柄會透過移至閉包中並傳遞給 `on_load_user_complete` 來儲存。\n當虛擬使用者載入時，將呼叫閉包，從而呼叫 `handle.resume()` 並重新渲染與暫停上下文相關的元件。\n\n:::\n\n# 完整範例\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // 略\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // 略\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // 如果用戶已加載，則將其作為 Ok(user) 返回。\n        Some(m) => Ok(m),\n        None => {\n            // 當使用者仍在載入時，我們建立一個 `Suspension`\n            // 並在資料載入完成時呼叫 `SuspensionHandle::resume`，\n            // 元件將自動重新渲染。\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### 在結構體組件中使用佔位標籤\n\n直接暫停結構體組件是不可能的。然而，您可以使用函數元件作為[高階元件](../advanced-topics/struct-components/hoc)來實現基於佔位標籤的資料取得。\n\nYew 倉庫中的[佔位標籤範例](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)示範如何使用這個元件。\n\n## 相關範例\n\n- [佔位標籤](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: '建立一個範例應用'\n---\n\n當您的環境準備好後，您可以選擇使用一個包含基本 Yew 應用所需樣板的起始模板，或手動設定一個小項目。\n\n## 使用模板快速起步\n\n請依照 [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) 的安裝說明安裝工具，然後執行下列指令：\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n## 手動設定應用\n\n### 建立項目\n\n首先，請建立一個新的 cargo 專案。\n\n```bash\ncargo new yew-app\n```\n\n開啟新建立的目錄。\n\n```bash\ncd yew-app\n```\n\n### 運行一個 hello world 範例\n\n為了驗證 Rust 環境是否設定正確，使用 `cargo run` 執行初始專案。您應該會看到一個 \"Hello World!\" 訊息。\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### 將項目設定為 Yew web 應用\n\n為了將這個簡單的命令列應用程式轉換為一個基本的 Yew web 應用程序，需要進行一些更改。\n\n#### 更新 Cargo.toml\n\n將 `yew` 加入到依賴清單中。\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在建立一個應用程序，你只需要 `csr` 特性。它將啟用 `Renderer` 和所有與客戶端渲染相關的程式碼。\n\n如果你正在製作一個函式庫，請不要啟用此特性，因為它會將客戶端渲染邏輯拉入伺服器端渲染包中。\n\n如果你需要 Renderer 進行測試或範例，你應該在 `dev-dependencies` 中啟用它。\n\n:::\n\n#### 更新 main.rs\n\n我們需要產生一個模板，設定一個名為 `App` 的根元件，該元件渲染一個按鈕，當點擊時更新其值。用以下程式碼取代 `src/main.rs` 的內容。\n\n:::note\n`main` 函數中的 `yew::Renderer::<App>::new().render()` 呼叫啟動您的應用程式並將其掛載到頁面的 `<body>` 標籤上。如果您想要使用任何動態屬性啟動您的應用程序，您可以使用 `yew::Renderer::<App>::with_props(..).render()`。\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### 建立 index.html\n\n最後，在應用程式的根目錄中新增一個 `index.html` 檔案。\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## 查看您的 Web 應用\n\n運行以下命令在本地建置和提供應用程式。\n\n```bash\ntrunk serve\n```\n\n:::info\n新增選項 '--open' 來開啟您的預設瀏覽器 `trunk serve --open`。\n:::\n\nTrunk 將在您修改任何原始程式碼檔案時即時重新建立您的應用程式。\n預設情況下，伺服器將在位址 '127.0.0.1' 的連接埠 '8080' 上監聽 => [http://localhost:8080](http://127.0.0.1:8080)。\n若要變更這部分配置，請建立以下檔案並根據需要進行編輯：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 區域網路上的監聽位址\naddress = \"127.0.0.1\"\n# 廣域網路上的監聽位址\n# address = \"0.0.0.0\"\n# 監聽的端口\nport = 8000\n```\n\n## 恭喜\n\n現在您已經成功設定了您的 Yew 開發環境，並建立了您的第一個 Web 應用程式。\n\n嘗試這個應用程序，並查看[範例](./examples.mdx)以進一步學習。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/getting-started/editor-setup.mdx",
    "content": "---\ntitle: '設定編輯器'\ndescription: '設定您的程式碼編輯器'\n---\n\n:::important 改進文檔\n有在使用不同的編輯器？如有推薦，請隨意新增您選擇的編輯器的說明。\n:::\n\n## 為建立元件新增模板\n\n### JetBrains IDEs\n\n1. 從導覽列依序點擊 File | Settings | Editor | Live Templates.\n2. 選擇 Rust 並點選 + 圖示新增新的 Live Template。\n3. 根據需要給它一個的名稱和描述。\n4. 將以下程式碼片段貼到範本文字部分。\n5. 在右下角更改適用性，選擇 Rust > Item > Module\n\n對於函數式元件，使用以下模板。\n\n- (可選) 點選編輯變量，並給 `tag` 一個合理的預設值，例如 \"div\"，用雙引號。\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\n對於結構體組件，可以使用以下更複雜的模板。\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. 從導覽列依序點選 File > Preferences > User Snippets.\n2. 選擇 Rust 作為設定語言。\n3. 在 JSON 檔案中加入以下程式碼片段：\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## 支援 `html!` 宏\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew 擴展\n\n> 這是一個**正在進行中**的，**由社區維護**的項目！ [請查看詳細信息，並將相關的 bug 報告/問題/疑問直接發送到擴展的存儲庫](https://github.com/TechTheAwesome/code-yew-server)\n\nRust-Yew 擴充 [可在 VSC Marketplace 上找到](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew)，提供語法高亮、重新命名、懸停等功能。\n\nEmmet 支援應該可以直接使用，如果不能，請回退到編輯 `settings.json` 檔案：\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> 下面的配置適用於[LazyVim](https://www.lazyvim.org) 配置和lazy.vim 插件，請在`lua/plugins/nvim-lspconfig.lua` 中建立一個檔案（或更新您的` lspconfig`）：\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/getting-started/examples.mdx",
    "content": "---\ntitle: '範例'\n---\n\nYew 倉庫包含許多[範例]（維護狀態各異）。\n我們建議瀏覽它們以了解如何使用框架的不同功能。\n我們也歡迎拉取請求和問題，以便在它們不可避免地被忽略並需要一些幫助 ♥️ 時使用。\n\n有關更多詳細信息，包括示例列表，請參閱[README]。\n\n:::note\n大多數範例都有一個可以在 https://examples.yew.rs/< example_name > 找到的線上部署。\n在各自的子資料夾中的 README 頁面上點擊它們的徽章以導航到線上演示。\n:::\n\n[範例清單]: https://github.com/yewstack/yew/tree/master/examples\n[範例文件 README]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/getting-started/introduction.mdx",
    "content": "---\ntitle: '開始使用'\n---\n\n你需要一些工具來編譯、建置、打包和調試你的 Yew 應用程式。在最開始，我們建議使用 [Trunk](https://trunkrs.dev/)。 Trunk 是用於 Rust 的 WASM Web 應用程式打包工具。\n\n## 安裝 Rust\n\n要安裝 Rust，請按照[官方說明](https://www.rust-lang.org/tools/install)。\n\n:::important\nYew 支援的最低 Rust 版本（MSRV）是 `1.84.0`。舊版將無法編譯。您可以使用 `rustup show`（在「active toolchain」下）或 `rustc --version` 檢查您的工具鏈版本。若要更新您的工具鏈，請執行 `rustup update`。\n:::\n\n## 安裝 WebAssembly 目標\n\nRust 可以為不同的「目標」（例如不同的處理器）編譯原始碼。用於基於瀏覽器的 WebAssembly 的編譯目標稱為 `wasm32-unknown-unknown`。以下命令將向您的開發環境新增 WebAssembly 目標。\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## 安裝 Trunk\n\nTrunk 是建議的管理部署和包裝的工具，並在整個文件和範例中使用。\n\n```shell\n# 需要注意的是，這可能需要一段時間來安裝，因為它會從頭開始編譯所有內容\n# Trunk 也為許多主要的套件管理器提供了預先建置的二進位文件\n# 有關更多詳細信息，請參見 https://trunkrs.dev/#install\ncargo install --locked trunk\n```\n\n### 其他選項\n\n除了 Trunk 之外，還有其他選項可用於打包 Yew 應用程式。您可能想嘗試以下選項之一：\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (仍在早期開發階段)\n\n## 下一步\n\n設定好開發環境後，現在可以繼續閱讀文件。如果您喜歡透過動手實作來學習，我們建議您查看我們的[教學](../tutorial)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: '從 0.22.0 遷移到 0.23.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` 不再在恆等分發時重新渲染\n\n`use_reducer` 現在在 reducer 返回相同的 `Rc` 時（透過指標相等性判斷）會跳過重新渲染。之前，每次分發都會觸發重新渲染。\n\n如果你的 reducer 有一個返回 `self` 不變的程式碼路徑，並且你依賴它來觸發重新渲染，請用 `use_force_update` 替代：\n\n<Tabs>\n  <TabItem value=\"before\" label=\"之前\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // 在 0.23 中這不再觸發重新渲染！\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"重新整理\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"之後\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"重新整理\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: '從 0.4.0 遷移到 0.5.0'\n---\n\n沒有破壞性變更。在 `Cargo.toml` 中將 yew-agent 更新到 0.5.0。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: '從 0.19.0 遷移到 0.20.0'\n---\n\n沒有破壞性變更。在 `Cargo.toml` 中將 yew-router 更新到 0.20.0。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\n一個關於如何最好地將CSS 支援整合到Yew 中的討論可以在這裡找到：[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\n這裡包含了很多關於如何最好地將 CSS 支援整合到 Yew 中的討論。\n\n目前，我們採用的方法是鼓勵開發者在採用最受歡迎的系統之前建立許多系統。\n\n社區目前正在開發幾個項目，以便為項目添加樣式。以下是其中的一些：\n\n#### 元件庫\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - 沒有任何 JavaScript 依賴的 Yew 樣式框架。\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design 元件。\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS 元件。\n- [Yewtify](https://github.com/yewstack/yewtify) – 在 Yew 中實作 Vuetify 框架所提供的功能。\n\n#### 樣式解決方案\n\n- [stylist](https://github.com/futursolo/stylist-rs) - 用於 WebAssembly 應用程式的 CSS-in-Rust 樣式解決方案。\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind 實用類別。\n\n:::important 改進文檔\n如果您正在開發一個為 Yew 添加樣式的項目，請提交一個 PR 將自己添加到這個列表中！\n:::\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/more/debugging.mdx",
    "content": "---\ntitle: '調試'\n---\n\n## 意外終止 (Panics)\n\nYew 會自動在瀏覽器控制台中輸出意外終止日誌。\n\n## 控制台日誌\n\n在 JavaScript 中，`console.log()` 用於輸出到瀏覽器控制台。以下是一些 Yew 的選項。\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate 與 [`log`](https://crates.io/crates/log) crate 集成，以將日誌等級、來源行和檔案名稱傳送到瀏覽器控制台。\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\n這個 crate 是 Gloo 的一部分，提供了對瀏覽器 API 的 Rust 包裝。 `log!` 巨集可以直接接受 `JsValue`，比 `wasm_logger` 更容易使用。\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` 可以與 [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) 一起使用，將訊息輸出到瀏覽器控制台。\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## 偵錯元件生命週期\n\n[`tracing`](https://crates.io/crates/tracing) 可用於收集與組件生命週期相關的事件資訊。 `tracing` 還附帶一個 `log` 支援的特性標誌，可以與 `wasm-logger` 很好地整合。\n\n[編譯時過濾器](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) 可以用於調整詳細程度或停用日誌記錄，這應該會導致更小的Wasm 檔案。\n\n## 來源映射 (Source Maps)\n\n有一些支援 [來源映射](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf)。但是，需要一些配置。\n\n## 過去的文章\n\n以下是一些關於 Rust 中 WebAssembly 偵錯狀態的過去文章。它們可能是有趣的閱讀。\n\n\\[Dec 2019\\] [Chrome DevTools 更新](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> 這些工作還有很多要做。例如，在工具方面，Emscripten（Binaryen）和 wasm-pack（wasm-bindgen）尚未支援在它們執行的轉換上更新 DWARF 資訊。\n\n\\[2020\\] [Rust Wasm 偵錯指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> 不幸的是，WebAssembly 的調試能力仍然不成熟。在大多數Unix 系統上，[DWARF](http://dwarfstd.org/) 用於編碼調試器需要提供運行中程序的源級檢查的信息，就連在Windows 上有一種編碼類似信息的替代格式。但目前，WebAssembly 並沒有對應的格式。\n\n\\[2019\\] [Rust Wasm 路線圖](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> 偵錯很棘手，因為很多情況不在這個工作小組的掌控之中，而是取決於 WebAssembly 標準化機構和實現瀏覽器開發者工具的人。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/more/deployment.mdx",
    "content": "---\ntitle: '部署'\ndescription: '部署 Yew 應用程式'\n---\n\n當您準備將 Yew 應用程式部署到伺服器時，您有多種部署方案可以選擇。\n\n`trunk build --release` 會以發布模式建立您的應用程式。設定您的HTTP 伺服器，以便在存取您的網站時提供`index.html`，並且對於靜態路徑（例如`index_<hash>.js` 和`index_bg_<hash>.wasm`）的請求，應該從trunk產生的dist 目錄中提供相應的內容。\n\n:::important 有關 `trunk serve --release`\n不要在生產環境中使用 `trunk serve --release` 來提供您的應用程式。\n它只應該用於在開發過程中測試發布版本建置。\n:::\n\n## 伺服器配置\n\n### 將 `index.html` 當作回退提供\n\n如果應用程式使用了 [Yew 路由](concepts/router.mdx)，您必須設定伺服器在請求不存在的檔案時傳回 `index.html`。\n\n具有 Yew 路由的應用程式被建構為 [單頁應用程式 (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA)。當使用者從正在執行的用戶端導覽到 URL 時，路由器會解釋 URL 並路由到該頁面。\n\n但是在刷新頁面或在網址列中輸入 URL 時，這些操作都是由瀏覽器本身處理的，而不是由正在執行的應用程式處理。瀏覽器直接向伺服器請求該 URL，繞過了路由器。錯誤配置的伺服器會回傳 404 - 未找到 狀態。\n\n透過返回 `index.html`，應用程式會像通常一樣加載，就好像請求是 `/`，直到路由器注意到路由是 `/show/42` 並顯示相應的內容。\n\n### 為 Web Assembly 資源配置正確的 MIME 類型。\n\nWASM 檔案必須使用 `application/wasm` MIME 類型設定 [Content-Type 頭](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。\n\n大多數伺服器和託管服務預設已經這樣做。如果您的伺服器沒有這樣做，請查閱其文件。在大多數 Web 瀏覽器中，錯誤的 MIME 類型會導致類似以下的錯誤：\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## 為相對路徑構建\n\n預設情況下，trunk 會假定您的網站在 `/` 處提供，並相應地建立網站。可以透過在 `index.html` 檔案中加入 `<base data-trunk-public-url />` 來覆寫此行為。 Trunk 會重寫此標籤以包含傳遞給 `--public-url` 的值。 Yew 路由會自動偵測 `<base />` 的存在並適當處理。\n\n## 使用環境變數自訂行為\n\n通常使用環境變數來自訂建構環境。由於應用程式在瀏覽器中運行，我們無法在運行時讀取環境變數。\n[`std::env!`](https://doc.rust-lang.org/std/macro.env.html) 巨集可以在編譯時取得環境變數的值。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/more/roadmap.mdx",
    "content": "---\ntitle: '路線圖'\ndescription: 'Yew 框架的計劃功能路線圖'\n---\n\n## 優先權\n\n框架即將推出的功能和重點的優先順序由社群決定。\n在 2020 年春季，我們發送了一份開發者調查，以收集關於專案方向的回饋。\n您可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到調查摘要。\n\n:::note\n所有主要倡議的狀態都可以在 Yew Github [專案看板](https://github.com/yewstack/yew/projects) 上跟踪\n:::\n\n## 重點\n\n1. 最受歡迎的功能\n2. 生產就緒\n3. 文件\n4. 痛點\n\n### 最受歡迎的功能\n\n1. [函數組件](https://github.com/yewstack/yew/projects/3)\n2. [元件庫](https://github.com/yewstack/yew/projects/4)\n3. 更好的狀態管理\n4. [伺服器端渲染](https://github.com/yewstack/yew/projects/5)\n\n### 生產就緒所需的問題\n\n- 提高 Yew 測試覆蓋率\n- 減少二進位檔案大小\n- [效能基準測試](https://github.com/yewstack/yew/issues/5)\n\n### 文件\n\n- 建立教程\n- 簡化項目設置\n\n### 痛點\n\n- [組件樣板](https://github.com/yewstack/yew/issues/830)\n- [代理](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/more/testing.mdx",
    "content": "---\ntitle: '測試應用'\ndescription: '測試你的應用程式'\n---\n\n:::info\n我們正在努力讓測試組件變得更容易，但目前仍在進行中。\n\n在 GitHub 倉庫中可以找到對 [淺渲染](https://github.com/yewstack/yew/issues/1413) 的支援。\n:::\n\n## 快照測試\n\nYew 提供了 `yew::tests::layout_tests` 模組來方便元件的快照測試。\n\n:::important 改進文檔\n我們需要幫助，以改進快照測試的文件。\n:::\n\n## wasm_bindgen_test\n\nRust/WASM 工作小組維護了一個稱為 [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html) 的 crate，\n它允許你以類似於內建的 `#[test]` 過程巨集的方式在瀏覽器中執行測試。\n有關此模組的更多信息，請參閱 [Rust Wasm 工作組的文檔](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23/tutorial/index.mdx",
    "content": "---\ntitle: '教學'\nslug: /tutorial\n---\n\n## 介紹\n\n在這個實作教程中，我們將學習如何使用 Yew 建立 Web 應用程式。\n**Yew** 是一個現代的 [Rust](https://www.rust-lang.org/) 框架，用於使用 [WebAssembly](https://webassembly.org/) 建立前端 Web 應用程式。\nYew 透過利用 Rust 強大的類型系統，鼓勵可重複使用、可維護和良好結構化的架構。\n一個龐大的社群所創造的函式庫生態系統，稱為Rust 中的[crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)，為常用模式（如狀態管理）提供了元件。\nRust 的套件管理器 [Cargo](https://doc.rust-lang.org/cargo/) 允許我們利用 [crates.io](https://crates.io) 上提供的大量 crate，例如 Yew。\n\n### 我們將要建構的內容\n\nRustconf 是 Rust 社群每年舉辦的星際派對。\nRustconf 2020 有大量的演講，提供了大量的資訊。\n在這個實作教程中，我們將建立一個 Web 應用程序，幫助其他 Rustaceans 了解這些演講並從一個頁面觀看它們。\n\n## 設定\n\n### 先決條件\n\n這個教程假設您已經熟悉 Rust。如果您是Rust 的新手，免費的[Rust 書](https://doc.rust-lang.org/book/ch00-00-introduction.html) 為初學者提供了一個很好的起點，並且即使對於有經驗的Rust 開發人員來說，它仍然是一個很好的資源。\n\n確保安裝了最新版本的 Rust，方法是執行 `rustup update` 或[安裝 Rust](https://www.rust-lang.org/tools/install)。\n\n安裝 Rust 後，您可以使用 Cargo 執行以下命令安裝 `trunk`：\n\n```bash\ncargo install trunk\n```\n\n我們還需要新增 WASM 建置目標，執行以下命令：\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### 設定項目\n\n首先，建立一個新的 cargo 專案：\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\n為了驗證 Rust 環境是否設定正確，使用 cargo 建置工具執行初始專案。\n在關於建置過程的輸出之後，您應該會看到預期的 \"Hello, world!\" 訊息。\n\n```bash\ncargo run\n```\n\n## 我們的第一個靜態頁面\n\n為了將這個簡單的命令列應用程式轉換為一個基本的 Yew web 應用程序，需要進行一些更改。\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\n如果你只是正在建立一個應用程序，你只需要 `csr` 特性。它將啟用 `Renderer` 和所有與客戶端渲染相關的程式碼。\n\n如果你正在製作一個函式庫，請不要啟用此特性，因為它會將客戶端渲染邏輯拉入伺服器端渲染包中。\n\n如果你需要 Renderer 進行測試或範例，你應該在 `dev-dependencies` 中啟用它。\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n現在，讓我們在專案的根目錄中建立一個 `index.html`。\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### 啟動開發伺服器\n\n運行以下命令建置並在本地提供應用程式。\n\n```bash\ntrunk serve --open\n```\n\n:::info\n刪除選項 '--open' 以在執行 `trunk serve` 後不開啟預設瀏覽器。\n:::\n\nTrunk 將在您修改任何原始程式碼檔案時即時重新建立您的應用程式。\n預設情況下，伺服器將在位址 '127.0.0.1' 的連接埠 '8080' 上監聽 => [http://localhost:8080](http://127.0.0.1:8080)。\n若要變更這部分配置，請建立以下檔案並根據需要進行編輯：\n\n```toml title=\"Trunk.toml\"\n[serve]\n# 區域網路上的監聽位址\naddress = \"127.0.0.1\"\n# 廣域網路上的監聽位址\n# address = \"0.0.0.0\"\n# 監聽的端口\nport = 8000\n```\n\n如果您有興趣，您可以執行 `trunk help` 和 `trunk help <subcommand>` 以獲取更多關於正在進行的流程的詳細資訊。\n\n### 恭喜\n\n您現在已經成功設定了 Yew 開發環境，並建立了您的第一個 Yew Web 應用程式。\n\n## 建立 HTML\n\nYew 利用了 Rust 的過程宏，並為我們提供了一種類似於 JSX（JavaScript 的擴展，可讓您在 JavaScript 中編寫類似 HTML 的程式碼）的語法來建立標記。\n\n### 轉換為經典 HTML\n\n由於我們已經對我們的網站長什麼樣子有了一個很好的想法，我們可以簡單地將我們的草稿轉換為與 `html!` 相容的表示。如果您習慣於編寫簡單的 HTML，那麼您在 `html!` 中編寫標記時應該沒有問題。要注意的是，這個巨集與 HTML 有一些不同之處：\n\n1. 表達式必須用大括號（`{ }`）括起來\n2. 只能有一個根節點。如果您想要在不將它們包裝在容器中的情況下擁有多個元素，可以使用空標籤/片段（`<> ... </>`）\n3. 元素必須正確關閉。\n\n我們想要建立一個佈局，原始 HTML 如下：\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\n現在，讓我們將這個 HTML 轉換為 `html!`。將下列程式碼片段輸入（或複製/貼上）到 `app` 函數的主體中，以便函數傳回 `html!` 的值\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\n刷新瀏覽器頁面，您應該看到以下輸出：\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### 在標記中使用 Rust 語言結構\n\n在 Rust 中編寫標記的一個很大的優勢是，我們在標記中獲得了 Rust 的所有優點。\n現在，我們不再在 HTML 中硬編碼影片列表，而是將它們定義為 `Vec` 的 `Video` 結構體。\n我們建立一個簡單的 `struct`（在 `main.rs` 或我們選擇的任何檔案中）來保存我們的資料。\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n接下來，我們將在 `app` 函數中建立這個結構體的實例，並使用它們來取代硬編碼的資料：\n\n```rust\nuse website_test::tutorial::Video; // 換成你自己的路徑\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\n為了顯示它們，我們需要將 `Vec` 轉換為 `Html`。我們可以透過建立一個迭代器，將其映射到 `html!` 並將其收集為 `Html` 來實現：\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\n在清單項目上使用鍵有助於 Yew 追蹤清單中哪些項目發生了變化，從而實現更快的重新渲染。 [始終建議在清單中使用鍵](/concepts/html/lists.mdx#keyed-lists)。\n:::\n\n最後，我們需要用從資料建立的 `Html` 取代硬編碼的影片清單：\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## 元件\n\n組件是 Yew 應用程式的構建塊。透過組合組件（可以由其他組件組成），我們建立我們的應用程式。透過為可重複使用性建立元件並保持它們的通用性，我們將能夠在應用程式的多個部分中使用它們，而無需重複程式碼或邏輯。\n\n到目前為止我們一直在使用的 `app` 函數是一個元件，稱為 `App`。它是一個「函數式元件」。\n\n1. 結構體組件\n2. 函數式組件\n\n在本教程中，我們將使用函數式元件。\n\n現在，讓我們將 `App` 元件拆分為更小的元件。我們首先將影片清單提取到自己的組件中。\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\n注意我們的 `VideosList` 函數元件的參數。函數元件只接受一個參數，該參數定義了它的 \"props\"（\"properties\" 的縮寫）。 Props 用於從父元件傳遞資料到子元件。在這種情況下，`VideosListProps` 是一個定義 props 的結構體。\n\n:::important\n用於 props 的結構體必須透過派生實作 `Properties`。\n:::\n\n為了讓上面的程式碼編譯通過，我們需要修改 `Video` 結構體如下：\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n現在，我們可以更新我們的 `App` 元件以使用 `VideosList` 元件。\n\n```rust ,ignore {4-7,13-14}\n#[component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n透過查看瀏覽器窗口，我們可以驗證清單是否按預期呈現。我們已經將清單的渲染邏輯移動到了它的元件中。這縮短了 `App` 元件的原始程式碼，使我們更容易閱讀和理解。\n\n### 使應用程式可以交互\n\n這裡的最終目標是顯示所選影片。為了做到這一點，`VideosList` 元件需要在選擇影片時「通知」其父元件，這是透過 `Callback` 完成的。這個概念稱為「傳遞處理程序」。我們修改其 props 以接受一個 `on_click` 回呼：\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\n然後我們修改 `VideosList` 元件以將所選影片傳遞給回呼。\n\n```rust ,ignore {2-4,6-12,15-16}\n#[component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\n接下來，我們需要修改 `VideosList` 的使用以傳遞該回呼。但在這樣做之前，我們應該建立一個新的元件 `VideoDetails`，當點擊影片時才會顯示。\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\n現在，修改 `App` 元件以在選擇影片時顯示 `VideoDetails` 元件。\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\n現在不用擔心 `use_state`，我們稍後會回到這個問題。注意我們用 `{ for details }` 提取列表資料的技巧。\n`Option<_>` 實作了`Iterator`，所以我們可以使用特殊的`{ for ... }` 語法來逐個顯示`Iterator` 返回的唯一元素，而這[由`html!` 巨集支援](concepts/html/lists)。\n\n### 處理狀態\n\n還記得之前使用的 `use_state` 嗎？那是一個特殊的函數，稱為 \"hook\"。 Hooks 用於 \"hook\" 到函數元件的生命週期中並執行操作。您可以在[這裡](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks)了解更多關於這個 hook 和其他 hook 的資訊。\n\n:::note\n結構體組件的行為不同。請查看[文件](advanced-topics/struct-components/introduction.mdx)以了解有關這些的資訊。\n:::\n\n## 取得資料（使用外部 REST API）\n\n在真實的應用程式中，資料通常來自 API 而不是硬編碼。讓我們從外部來源取得我們的影片清單。為此，我們需要添加以下 crate：\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  用於進行 fetch 調用。\n- [`serde`](https://serde.rs) 及其衍生特性\n  用於反序列化 JSON 回應\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  用於將 Rust 的 Future 作為 Promise 執行\n\n讓我們更新 `Cargo.toml` 檔案中的依賴項：\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.6\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\n在選擇依賴項時，請確保它們與 `wasm32` 相容！否則，您將無法運行您的應用程式。\n:::\n\n更新 `Video` 結構體以衍生 `Deserialize` 特性：\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\n最後一步，我們需要更新我們的 `App` 元件，以便進行 fetch 請求，而不是使用硬編碼的數據\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\n我們在這裡使用 `unwrap`，因為這是一個演示應用程式。在真實的應用程式中，您可能希望有[適當的錯誤處理](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)。\n:::\n\n現在，查看瀏覽器，看看一切是否按預期工作……如果不是因為 CORS 的話。為了解決這個問題，我們需要一個代理伺服器。幸運的是 trunk 提供了這個功能。\n\n更新這些行：\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\n現在，使用以下命令重新運行伺服器：\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\n刷新網頁，一切都應該按預期工作。\n\n## 總結\n\n恭喜！您已經建立了一個從外部 API 取得資料並顯示影片清單的 Web 應用程式。\n\n## 接下來\n\n這個應用程式離完美或有用還有很長的路要走。完成本教學後，您可以將其作為探索更高級主題的起點。\n\n### 樣式\n\n我們的應用程式看起來非常醜陋。沒有 CSS 或任何樣式。不幸的是，Yew 沒有提供內建的樣式組件。請查看 [Trunk 的 assets](https://trunkrs.dev/assets/)，以了解如何新增樣式表。\n\n### 更多依賴函式庫\n\n我們的應用程式只使用了很少的外部依賴。有很多 crate 可以使用。請查看[外部程式庫](/community/external-libs)以取得更多詳細資訊。\n\n### 了解更多關於 Yew\n\n閱讀我們的[官方文件](../getting-started/introduction.mdx)。它更詳細地解釋了許多概念。要了解有關 Yew API 的更多信息，請查看我們的[API 文件](https://docs.rs/yew)。\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs/version-0.23.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"0.23\",\n    \"description\": \"The label for version 0.23\"\n  },\n  \"sidebar.docs.category.Getting Started\": {\n    \"message\": \"從零開始\",\n    \"description\": \"The label for category Getting Started in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts\": {\n    \"message\": \"核心觀念\",\n    \"description\": \"The label for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.title\": {\n    \"message\": \"Yew concepts\",\n    \"description\": \"The generated-index page title for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.Concepts.link.generated-index.description\": {\n    \"message\": \"Learn about the important Yew concepts!\",\n    \"description\": \"The generated-index page description for category Concepts in sidebar docs\"\n  },\n  \"sidebar.docs.category.HTML\": {\n    \"message\": \"HTML\",\n    \"description\": \"The label for category HTML in sidebar docs\"\n  },\n  \"sidebar.docs.category.Components\": {\n    \"message\": \"Function Components\",\n    \"description\": \"The label for category Components in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics\": {\n    \"message\": \"進階主題\",\n    \"description\": \"The label for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.title\": {\n    \"message\": \"進階主題\",\n    \"description\": \"The generated-index page title for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.Advanced topics.link.generated-index.description\": {\n    \"message\": \"Learn about the advanced topics and inner workings of Yew!\",\n    \"description\": \"The generated-index page description for category Advanced topics in sidebar docs\"\n  },\n  \"sidebar.docs.category.More\": {\n    \"message\": \"更多\",\n    \"description\": \"The label for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.More.link.generated-index.title\": {\n    \"message\": \"Miscellaneous\",\n    \"description\": \"The generated-index page title for category More in sidebar docs\"\n  },\n  \"sidebar.docs.category.Migration guides\": {\n    \"message\": \"Migration guides\",\n    \"description\": \"The label for category Migration guides in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew\": {\n    \"message\": \"yew\",\n    \"description\": \"The label for category yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-agent\": {\n    \"message\": \"yew-agent\",\n    \"description\": \"The label for category yew-agent in sidebar docs\"\n  },\n  \"sidebar.docs.category.yew-router\": {\n    \"message\": \"yew-router\",\n    \"description\": \"The label for category yew-router in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew\": {\n    \"message\": \"Intro With Basic Web Technologies\",\n    \"description\": \"The label for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.title\": {\n    \"message\": \"Yew Take on Basic Web Technologies\",\n    \"description\": \"The generated-index page title for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Using Basic Web Technologies In Yew.link.generated-index.description\": {\n    \"message\": \"Yew mostly operates on the idea of keeping everything that a reusable piece of UI may need, in one place - rust files. But also seeks to stay close to the original look of the technology. Explore further to fully grasp what we mean by these statements:\",\n    \"description\": \"The generated-index page description for category Using Basic Web Technologies In Yew in sidebar docs\"\n  },\n  \"sidebar.docs.category.Hooks\": {\n    \"message\": \"Hooks\",\n    \"description\": \"The label for category Hooks in sidebar docs\"\n  },\n  \"sidebar.docs.category.Struct Components\": {\n    \"message\": \"Struct Components\",\n    \"description\": \"The label for category Struct Components in sidebar docs\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs-community/current.json",
    "content": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-docs-router/current.json",
    "content": "{\n    \"version.label\": {\n        \"message\": \"Next\",\n        \"description\": \"The label for version current\"\n    }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-plugin-content-pages/index.mdx",
    "content": "---\ntitle: 簡介\nslug: /\n---\n\n## 什麼是 Yew？\n\n**Yew** 是現代化的 [Rust](https://www.rust-lang.org/) 框架，使用 [WebAssembly](https://webassembly.org/) 來開發多執行緒的網頁前端應用程式\n\n- **基於元件的框架**，可以輕鬆開發互動的使用者介面 \\(UI\\)。有使用過 [React](https://reactjs.org/) 與 [Elm](https://elm-lang.org/) 的開發者在使用 Yew 的時候更容易上手。\n- **高效能**，減少 DOM API 的呼叫次數，並幫助開發者輕鬆的將行程分流到背景的 web workers 中執行\n- **與 JavaScript 互通**，允許開發者使用 NPM 的套件，並可以與現有的 JavaScript 應用程式整合\n\n### 加入我們 😊\n\n- 你可以在 [GitHub issues page](https://github.com/yewstack/yew/issues) 回報 bugs 及針對功能進行討論\n- 我們歡迎大家多發 PR \\(pull request\\)。 如果你有興趣與我們一起開發，別忘了先閱讀 [good first issues](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) ！\n- 我們 [Gitter](https://gitter.im/yewframework/Lobby) 聊天室非常活躍，歡迎提問\n\n### 準備好「潛」入了嗎？\n\n點選下列的連結學習如何建立一個 Yew 應用程式並且從社群的範例專案中學習\n\n[專案設定](docs/getting-started/introduction)\n\n### 還在猶豫嗎？\n\n這個專案是建立在最新穎的科技之上，對於想要打造未來基礎專案的開發者而言是絕佳的選擇。以下是我們認為 Yew 會成為網路開發未來式的幾個理由。\n\n#### 等等，為何選擇 WebAssembly ？\n\nWebAssembly \\(Wasm\\) 是一個可攜式的低階語言也是 Rust 的編譯目標之一。它在瀏覽器中具有原生的執行速度且可以跟 JavaScript 相互協作還得到所有主要瀏覽器的支援。如果你想知道如何在應用程式中充分利用 WebAssembly ，不妨檢閱這個[使用情境](https://webassembly.org/docs/use-cases/)列表。\n\n注意， Wasm （尚且）不是改善網路應用程式效能的萬靈丹。最少目前為止，在使用 DOM API 上 Wasm 仍然比不上直接以 JavaScript 呼叫。但這僅是暫時的問題， [WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) 提案正是以它作為解決的目標。如果你想瞭解更多有這個議題的資訊，別忘了檢閱這篇 Mozilla 的[超棒文章](https://hacks.mozilla.org/2019/08/webassembly-interface-types/)。\n\n#### 好的，但為什麼是 Rust 呢？\n\nRust 的速度極快，同時豐富的型別系統和所有權模型也讓它非常可靠。雖然它的學習曲線陡峭，但這些付出會非常值得。Rust 也分別在 [2016](https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted) 、 [2017](https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted) 、 [2018](https://insights.stackoverflow.com/survey/2018#technology-_-most-loved-dreaded-and-wanted-languages) 、 [2019](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages) 連續四年在 Stack Overflow 的開發者調查中獲選為最喜愛的程式設計語言。\n\nRust 豐富的型別系統及所有權模型協助開發者撰寫更加安全的程式碼。忘了 JavaScript 中難以追蹤的競賽條件吧！在多數情況下 Rust 的編譯器甚至可以在你的應用程式執行前就把 bug 抓出來。而且就算你的應用程式真的在執行時發生了錯誤，你仍然可以在瀏覽器控制台中取得 Rust 程式碼的完整堆疊追蹤。\n\n#### 有其他選擇嗎？\n\n我們喜愛跟其他專案分享點子而且相信在互相幫助之下可以激發這個最新科技的全部潛能。如果你不是 Yew 的一份子，那你或許會想要關注這些專案。\n\n- [Percy](https://github.com/chinedufn/percy) —_「 Rust + WebAssembly 的模組化工具組，用於建立同購的網路應用程式」_\n- [Seed](https://github.com/seed-rs/seed) —_「建立網路應用程式的 Rust 框架」_\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-theme-classic/footer.json",
    "content": "{\n  \"link.title.Support\": {\n    \"message\": \"Support\",\n    \"description\": \"The title of the footer links column with title=Support in the footer\"\n  },\n  \"link.title.Participate\": {\n    \"message\": \"Participate\",\n    \"description\": \"The title of the footer links column with title=Participate in the footer\"\n  },\n  \"link.title.More\": {\n    \"message\": \"More\",\n    \"description\": \"The title of the footer links column with title=More in the footer\"\n  },\n  \"link.item.label.Sponsor Project\": {\n    \"message\": \"Sponsor Project\",\n    \"description\": \"The label of footer link with label=Sponsor Project linking to https://opencollective.com/yew\"\n  },\n  \"link.item.label.GitHub\": {\n    \"message\": \"GitHub\",\n    \"description\": \"The label of footer link with label=GitHub linking to https://github.com/yewstack/yew\"\n  },\n  \"link.item.label.Discord\": {\n    \"message\": \"Discord\",\n    \"description\": \"The label of footer link with label=Discord linking to https://discord.gg/VQck8X4\"\n  },\n  \"link.item.label.Twitter\": {\n    \"message\": \"Twitter\",\n    \"description\": \"The label of footer link with label=Twitter linking to https://twitter.com/yewstack\"\n  },\n  \"link.item.label.Yew Awesome\": {\n    \"message\": \"Yew Awesome\",\n    \"description\": \"The label of footer link with label=Yew Awesome linking to https://github.com/jetli/awesome-yew\"\n  }\n}\n"
  },
  {
    "path": "website/i18n/zh-Hant/docusaurus-theme-classic/navbar.json",
    "content": "{\n  \"title\": {\n    \"message\": \"Yew\",\n    \"description\": \"The title in the navbar\"\n  },\n  \"item.label.Docs\": {\n    \"message\": \"Docs\",\n    \"description\": \"Navbar item with label Docs\"\n  },\n  \"item.label.API\": {\n    \"message\": \"API\",\n    \"description\": \"Navbar item with label API\"\n  },\n  \"item.label.GitHub\": {\n    \"message\": \"GitHub\",\n    \"description\": \"Navbar item with label GitHub\"\n  },\n  \"item.label.Community\": {\n    \"message\": \"Community\",\n    \"description\": \"Navbar item with label Community\"\n  },\n  \"item.label.Tutorial\": {\n    \"message\": \"Tutorial\",\n    \"description\": \"Navbar item with label Tutorial\"\n  },\n  \"item.label.Blog\": {\n    \"message\": \"Blog\",\n    \"description\": \"Navbar item with label Blog\"\n  },\n  \"item.label.Playground\": {\n    \"message\": \"Playground\",\n    \"description\": \"Navbar item with label Playground\"\n  },\n  \"logo.alt\": {\n    \"message\": \"Yew Logo\",\n    \"description\": \"The alt text of navbar logo\"\n  }\n}\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n    \"name\": \"yew-docs\",\n    \"version\": \"0.0.0\",\n    \"private\": true,\n    \"scripts\": {\n        \"docusaurus\": \"docusaurus\",\n        \"start\": \"docusaurus start\",\n        \"build\": \"docusaurus build\",\n        \"swizzle\": \"docusaurus swizzle\",\n        \"deploy\": \"docusaurus deploy\",\n        \"clear\": \"docusaurus clear\",\n        \"serve\": \"docusaurus serve\",\n        \"check-translations\": \"node ./check-translations.js\",\n        \"write-translations\": \"node ./write-translations.js\",\n        \"write-heading-ids\": \"docusaurus write-heading-ids\",\n        \"fmt\": \"prettier --check .\",\n        \"fmt:write\": \"prettier --write .\"\n    },\n    \"dependencies\": {\n        \"@docusaurus/core\": \"^3.9.1\",\n        \"@docusaurus/plugin-client-redirects\": \"^3.9.1\",\n        \"@docusaurus/preset-classic\": \"^3.9.1\",\n        \"@mdx-js/react\": \"^3.1.1\",\n        \"@svgr/webpack\": \"^8.1.0\",\n        \"clsx\": \"^2.1.1\",\n        \"docusaurus-plugin-sass\": \"^0.2.6\",\n        \"file-loader\": \"^6.2.0\",\n        \"react\": \"^19.1.1\",\n        \"react-dom\": \"^19.1.1\",\n        \"sass\": \"^1.93.2\",\n        \"url-loader\": \"^4.1.1\",\n        \"yew-docs\": \"file:\"\n    },\n    \"browserslist\": {\n        \"production\": [\n            \">0.5%\",\n            \"not dead\",\n            \"not op_mini all\"\n        ],\n        \"development\": [\n            \"last 1 chrome version\",\n            \"last 1 firefox version\",\n            \"last 1 safari version\"\n        ]\n    },\n    \"engines\": {\n        \"node\": \">=18.0\"\n    },\n    \"devDependencies\": {\n        \"@docusaurus/module-type-aliases\": \"^3.0.0\",\n        \"@docusaurus/tsconfig\": \"3.9.1\",\n        \"@types/react\": \"^19.1.16\",\n        \"@types/react-helmet\": \"^6.1.11\",\n        \"@types/react-router-dom\": \"^5.3.3\",\n        \"@typescript-eslint/eslint-plugin\": \"^8.45.0\",\n        \"@typescript-eslint/parser\": \"^8.22.0\",\n        \"dir-compare\": \"^5.0.0\",\n        \"prettier\": \"^3.6.2\",\n        \"typescript\": \"^5.9.3\"\n    }\n}\n"
  },
  {
    "path": "website/sidebars/community.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n The sidebars can be generated from the filesystem, or explicitly defined here.\n Create as many sidebars as you want.\n */\n\nmodule.exports = {\n    community: [{ type: 'autogenerated', dirName: '.' }],\n}\n"
  },
  {
    "path": "website/sidebars/docs.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n The sidebars can be generated from the filesystem, or explicitly defined here.\n Create as many sidebars as you want.\n */\n\nmodule.exports = {\n    docs: [\n        {\n            type: 'category',\n            label: 'Getting Started',\n            link: { type: 'doc', id: 'getting-started/introduction' },\n            items: [\n                'getting-started/build-a-sample-app',\n                'getting-started/examples',\n                'getting-started/editor-setup',\n            ],\n        },\n        {\n            type: 'category',\n            label: 'Concepts',\n            link: {\n                type: 'generated-index',\n                title: 'Yew concepts',\n                description: 'Learn about the important Yew concepts!',\n            },\n            items: [\n                {\n                    type: 'category',\n                    label: 'Using Basic Web Technologies In Yew',\n                    link: {\n                        type: 'generated-index',\n                        title: \"Yew's Take on Basic Web Technologies\",\n                        description:\n                            'Yew centrally operates on the idea of keeping everything that a reusable piece of UI may need' +\n                            'in one place - rust files, while also keeping the underlying technology accessible where necessary. ' +\n                            'Explore further to fully grasp what we mean by these statements:',\n                    },\n                    items: [\n                        'concepts/basic-web-technologies/html',\n                        'concepts/basic-web-technologies/css',\n                        'concepts/basic-web-technologies/js',\n                        'concepts/basic-web-technologies/wasm-bindgen',\n                        'concepts/basic-web-technologies/web-sys',\n                    ],\n                },\n                {\n                    type: 'category',\n                    label: 'Components',\n                    link: {\n                        type: 'doc',\n                        id: 'concepts/function-components/introduction',\n                    },\n                    items: [\n                        'concepts/function-components/properties',\n                        'concepts/function-components/callbacks',\n                        'concepts/function-components/children',\n                        'concepts/function-components/pure-components',\n                        {\n                            type: 'category',\n                            label: 'Hooks',\n                            link: {\n                                type: 'doc',\n                                id: 'concepts/function-components/hooks/introduction',\n                            },\n                            items: [\n                                'concepts/function-components/hooks/custom-hooks',\n                            ],\n                        },\n                        'concepts/function-components/node-refs',\n                        'concepts/function-components/state',\n                        'concepts/function-components/communication',\n                        'concepts/function-components/generics',\n                    ],\n                },\n                {\n                    type: 'category',\n                    label: 'HTML',\n                    link: { type: 'doc', id: 'concepts/html/introduction' },\n                    items: [\n                        'concepts/html/components',\n                        'concepts/html/elements',\n                        'concepts/html/events',\n                        'concepts/html/classes',\n                        'concepts/html/fragments',\n                        'concepts/html/lists',\n                        'concepts/html/literals-and-expressions',\n                        'concepts/html/conditional-rendering',\n                    ],\n                },\n                'concepts/agents',\n                'concepts/contexts',\n                'concepts/router',\n                'concepts/suspense',\n            ],\n        },\n        {\n            type: 'category',\n            label: 'Advanced topics',\n            link: {\n                type: 'generated-index',\n                title: 'Advanced topics',\n                description:\n                    'Learn about the advanced topics and inner workings of Yew!',\n            },\n            items: [\n                'advanced-topics/how-it-works',\n                {\n                    type: 'category',\n                    label: 'Struct Components',\n                    link: {\n                        type: 'doc',\n                        id: 'advanced-topics/struct-components/introduction',\n                    },\n                    items: [\n                        'advanced-topics/struct-components/hoc',\n                        'advanced-topics/struct-components/lifecycle',\n                        'advanced-topics/struct-components/scope',\n                        'advanced-topics/struct-components/callbacks',\n                        'advanced-topics/struct-components/properties',\n                        'advanced-topics/struct-components/refs',\n                    ],\n                },\n                'advanced-topics/children',\n                'advanced-topics/optimizations',\n                'advanced-topics/portals',\n                'advanced-topics/server-side-rendering',\n                'advanced-topics/immutable',\n            ],\n        },\n        {\n            type: 'category',\n            label: 'More',\n            link: {\n                type: 'generated-index',\n                title: 'Miscellaneous',\n            },\n            items: [\n                'more/debugging',\n                'more/deployment',\n                'more/css',\n                'more/testing',\n                'more/roadmap',\n            ],\n        },\n        {\n            type: 'category',\n            label: 'Migration guides',\n            items: [\n                {\n                    type: 'category',\n                    label: 'yew',\n                    items: [\n                        'migration-guides/yew/from-0_22_0-to-0_23_0',\n                        'migration-guides/yew/from-0_21_0-to-0_22_0',\n                        'migration-guides/yew/from-0_20_0-to-0_21_0',\n                        'migration-guides/yew/from-0_19_0-to-0_20_0',\n                    ],\n                },\n                {\n                    type: 'category',\n                    label: 'yew-agent',\n                    items: [\n                        'migration-guides/yew-agent/from-0_4_0-to-0_5_0',\n                        'migration-guides/yew-agent/from-0_3_0-to-0_4_0',\n                        'migration-guides/yew-agent/from-0_1_0-to-0_2_0',\n                        'migration-guides/yew-agent/from-0_0_0-to-0_1_0',\n                    ],\n                },\n                {\n                    type: 'category',\n                    label: 'yew-router',\n                    items: [\n                        'migration-guides/yew-router/from-0_19_0-to-0_20_0',\n                        'migration-guides/yew-router/from-0_16_0-to-0_17_0',\n                        'migration-guides/yew-router/from-0_15_0-to-0_16_0',\n                    ],\n                },\n            ],\n        },\n    ],\n    api: [{ type: 'autogenerated', dirName: 'tutorial' }],\n}\n"
  },
  {
    "path": "website/src/constants.js",
    "content": "module.exports = {\n    API_BUTTON: 'API',\n}\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n    --ifm-color-primary: #00755a;\n    --ifm-color-primary-dark: #006951;\n    --ifm-color-primary-darker: #00634d;\n    --ifm-color-primary-darkest: #00523f;\n    --ifm-color-primary-light: #008163;\n    --ifm-color-primary-lighter: #008768;\n    --ifm-color-primary-lightest: #009875;\n}\n\n:root[data-theme='dark'] {\n    --ifm-color-primary: #28d2ad;\n    --ifm-color-primary-dark: #24bd9c;\n    --ifm-color-primary-darker: #22b393;\n    --ifm-color-primary-darkest: #1c9379;\n    --ifm-color-primary-light: #3ad9b7;\n    --ifm-color-primary-lighter: #44dbba;\n    --ifm-color-primary-lightest: #64e1c6;\n    --docusaurus-highlighted-code-line-bg: rgb(55 60 75);\n}\n"
  },
  {
    "path": "website/src/pages/index.module.scss",
    "content": "@mixin devices($breakpoint) {\n    @if $breakpoint == desktop {\n        @media only screen and (min-width: 700px) {\n            @content;\n        }\n    }\n\n    @if $breakpoint == tablet {\n        @media only screen and (min-width: 700px) {\n            @content;\n        }\n    }\n\n    @if $breakpoint == mobile {\n        @media only screen and (min-width: 350px) {\n            @content;\n        }\n    }\n}\n\n.heroHeader {\n    flex-direction: column;\n}\n\n.heroSubtitle {\n    @include devices(mobile) {\n        padding: 1rem;\n        text-align: center;\n    }\n}\n\n.header {\n    display: flex;\n    padding: var(--ifm-h1-font-size);\n    gap: calc(var(--ifm-h1-font-size) / 2);\n    align-items: center;\n    justify-content: center;\n\n    h1 {\n        @include devices(desktop) {\n            --ifm-h1-font-size: calc(var(--ifm-h1-font-size) * 3);\n        }\n        @include devices(tablet) {\n            --ifm-h1-font-size: calc(var(--ifm-h1-font-size) * 1.5);\n        }\n    }\n\n    img {\n        $dimensions: calc(var(--ifm-h1-font-size) * 5);\n\n        width: $dimensions;\n        height: $dimensions;\n\n        @include devices(tablet) {\n            $dimensions: calc(var(--ifm-h1-font-size) * 3);\n        }\n    }\n}\n\n.callToActions {\n    display: flex;\n    flex-direction: column;\n\n    @include devices(desktop) {\n        flex-direction: row;\n    }\n}\n\n.features {\n    h2 {\n        font-size: calc(var(--ifm-h2-font-size) * 1.5);\n\n        @include devices(mobile) {\n            font-size: calc(var(--ifm-h2-font-size) * 1.5);\n        }\n    }\n\n    .featuresGrid {\n        $spacing: 2rem;\n        padding: $spacing;\n        display: grid;\n\n        grid-template-columns: 1fr;\n        gap: ($spacing * 2);\n\n        @include devices(tablet) {\n            grid-template-columns: repeat(3, 1fr);\n            gap: $spacing;\n        }\n    }\n}\n"
  },
  {
    "path": "website/src/pages/index.tsx",
    "content": "import React from 'react'\nimport Layout from '@theme/Layout'\nimport styles from './index.module.scss'\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext'\nimport clsx from 'clsx'\nimport IconExternalLink from '@theme/Icon/ExternalLink'\nimport Link from '@docusaurus/Link'\n\nconst Hero = () => {\n    const { siteConfig } = useDocusaurusContext()\n\n    return (\n        <div className={clsx('hero shadow--lw', styles.heroHeader)}>\n            <section className={styles.header}>\n                <img src={siteConfig.favicon} alt=\"Logo\" />\n                <h1 className=\"hero__title\">{siteConfig.title}</h1>\n            </section>\n            <section className={clsx('hero__subtitle', styles.heroSubtitle)}>\n                {siteConfig.tagline}\n            </section>\n            <section className={styles.callToActions}>\n                <Link\n                    className=\"button button--lg button--outline button--primary margin--lg\"\n                    to=\"/docs/getting-started/introduction\"\n                >\n                    Get Started\n                </Link>\n                <Link\n                    className=\"button button--lg button--outline button--link margin--lg\"\n                    to=\"https://play.yew.rs\"\n                    target=\"_blank\"\n                >\n                    Playground\n                    <IconExternalLink />\n                </Link>\n            </section>\n        </div>\n    )\n}\n\nconst FEATURES = [\n    {\n        header: 'Component Based',\n        body: 'Features a component-based framework which makes it easy to create interactive UIs. Developers who have experience with frameworks like React and Elm should feel quite at home when using Yew.',\n        to: '/docs/next/concepts/function-components',\n    },\n    {\n        header: 'HTML macro',\n        body: 'Features a macro for declaring interactive HTML with Rust expressions. Developers who have experience using JSX in React should feel quite at home when using Yew.',\n        to: '/docs/next/concepts/html',\n    },\n    {\n        header: 'Server Side Rendering',\n        body: 'Features server side rendering for all the SEO and enhancements of server-rendered app while keeping the feel of an SPA',\n        to: '/docs/next/advanced-topics/server-side-rendering',\n    },\n]\n\nfunction Feature(props: { feature: (typeof FEATURES)[number] }) {\n    return (\n        <div className=\"card-demo\">\n            <div className=\"card\">\n                <div className=\"card__header\">\n                    <h3>{props.feature.header}</h3>\n                </div>\n                <div className=\"card__body\">\n                    <p>{props.feature.body}</p>\n                </div>\n                <div className=\"card__footer\">\n                    <Link\n                        className=\"button button--secondary\"\n                        to={props.feature.to}\n                    >\n                        Learn more\n                    </Link>\n                </div>\n            </div>\n        </div>\n    )\n}\n\nfunction Features() {\n    return (\n        <article className={clsx('padding--lg', styles.features)}>\n            <h2>Features</h2>\n            <section className={styles.featuresGrid}>\n                {FEATURES.map((it) => (\n                    <Feature feature={it} />\n                ))}\n            </section>\n        </article>\n    )\n}\n\nexport default function Index() {\n    const { siteConfig } = useDocusaurusContext()\n    return (\n        <Layout description={siteConfig.tagline}>\n            <Hero />\n            <Features />\n        </Layout>\n    )\n}\n"
  },
  {
    "path": "website/src/theme/NavbarItem/DefaultNavbarItem.tsx",
    "content": "import React from 'react'\nimport { useLocation } from '@docusaurus/router'\nexport * from '@theme-original/NavbarItem/DefaultNavbarItem'\nimport OriginalNavbarItem from '@theme-original/NavbarItem/DefaultNavbarItem'\nimport { API_BUTTON } from '../../constants.js'\n\nconst VERSION_REGEX = /\\/docs\\/(0.([0-9]+)(\\.[0-9]+)?|next)?/\nconst API_BASE_URLS = {\n    next: 'https://api.yew.rs/next/yew',\n    default: 'https://docs.rs/yew',\n}\n\n/**\n * @returns {string}\n */\nconst useVersion = () => {\n    const location = useLocation()\n    const match = location.pathname.match(VERSION_REGEX)\n    return match ? (match[1] ?? '') : ''\n}\n\n/**\n * @param {string} version\n * @returns {string}\n */\nconst getApiUrl = (version) => {\n    if (version === 'next') {\n        return API_BASE_URLS.next\n    }\n    return version\n        ? `${API_BASE_URLS.default}/${version}`\n        : API_BASE_URLS.default\n}\n\n/**\n * @param {Object} props\n * @param {string} props.label\n * @returns {React.ReactElement}\n */\nexport default function DefaultNavbarItem(props) {\n    const { label, ...restProps } = props\n\n    if (label === API_BUTTON) {\n        const version = useVersion()\n        const href = getApiUrl(version)\n        return <OriginalNavbarItem {...restProps} label={label} href={href} />\n    }\n\n    return <OriginalNavbarItem {...props} />\n}\n"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  },
  {
    "path": "website/static/tutorial/data.json",
    "content": "[\n    {\n        \"id\": 1,\n        \"title\": \"Building and breaking things\",\n        \"speaker\": \"John Doe\",\n        \"url\": \"https://youtu.be/PsaFVLr8t4E\"\n    },\n    {\n        \"id\": 2,\n        \"title\": \"The development process\",\n        \"speaker\": \"Jane Smith\",\n        \"url\": \"https://youtu.be/PsaFVLr8t4E\"\n    },\n    {\n        \"id\": 3,\n        \"title\": \"The Web 7.0\",\n        \"speaker\": \"Matt Miller\",\n        \"url\": \"https://youtu.be/PsaFVLr8t4E\"\n    },\n    {\n        \"id\": 4,\n        \"title\": \"Mouseless development\",\n        \"speaker\": \"Tom Jerry\",\n        \"url\": \"https://youtu.be/PsaFVLr8t4E\"\n    }\n]\n"
  },
  {
    "path": "website/tsconfig.json",
    "content": "{\n    \"extends\": \"@docusaurus/tsconfig\",\n    \"include\": [\"src/\"]\n}\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Children, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Children,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: 'Low level details about the framework'\n---\n\n# Low-level library internals\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated to the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing the\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magic, but it has nothing to hide. If you're curious about\nhow it works, try expanding the `html!` macro calls in your program. There's a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` isn't shipped with\n`cargo` by default so you'll need to install it with `cargo install cargo-expand` if you haven't\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. In order to prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we're\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be really helpful for libraries which promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. In order to\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: 'Optimizations & Best Practices'\nsidebar_label: Optimizations\ndescription: 'Make your app faster'\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nIn an effort to avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better, if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin for pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, it also adds unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component, or just a big\nfunction that produces `Html`. Code which is shared between the crates containing different parts of\nthe application could be stored in a separate crate which is depended on throughout the project.\nIn the best case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and render the component you are working on on top of that.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther more it is possible to optimize size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading:\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns a `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Children,\n}\n\n#[function_component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        html!{ {for props.children.iter()} },\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/portals)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/server-side-rendering.md",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render at the client side. When a viewer\nvisits a website, the server sends a skeleton html file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered at the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and initial render has completed.\n   This can result in poor user experience if the user is using a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver-side.\n\nTo render Yew components at the server-side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with_deps`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server-side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with_deps` as effects are not executed during server side\nrendering.\n\n:::\n\n:::danger Struct Components\n\nWhilst it's possible to use Struct Components with server-side rendering,\nthere's no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult point with server side rendering\nand hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual dom to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there's no mechanism for Yew to detect whether a component is still\nfetching data. The data fetching client is responsible to implement\na solution to detect what's being requested during initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nNot only this wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on\nthe server-side available during hydration process to make sure that the\nvirtual dom returned by initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client-side,\nprovides a way to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server-side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR ready\napplication with data fetching with very little effort.\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable html string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of start rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the html string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an html representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of the your\ncomponent is side-effect free. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into an `use_effect` hook.\n\nIt's possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/ssr_router)\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function which takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/timer)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components dont directly support a feature (ex. Suspense) or require a lot of boiler plate to use the features (ex. Context).\n\nIn those cases it is recommended to create function components that are higher order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that dont add any new Html and only wrap some other component to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[function_component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage their own state and can render themselves to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses syntax which is similar to HTML but is not exactly the same. The rules are also\nmuch stricter. It also provides super-powers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it's used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parent and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'Lifecycle'\ndescription: 'Components and their lifecycle hooks'\n---\n\nThe `Component` trait has a number of methods which need to be implemented; Yew will call these at different\nstages in the lifecycle of a component.\n\n## Lifecycle\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## Lifecycle Methods\n\n### Create\n\nWhen a component is created, it receives properties from its parent component and is stored within\nthe `Context<Self>` that's passed down to the `create` method. The properties can be used to\ninitialize the component's state and the \"link\" can be used to register callbacks or send messages to the component.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nThe `view` method allows you to describe how a component should be rendered to the DOM. Writing\nHTML-like code using Rust functions can become quite messy, so Yew provides a macro called `html!`\nfor declaring HTML and SVG nodes (as well as attaching attributes and event listeners to them) and a\nconvenient way to render child components. The macro is somewhat similar to React's JSX (the\ndifferences in programming language aside).\nOne difference is that Yew provides a shorthand syntax for properties, similar to Svelte, where instead of writing `onclick={onclick}`, you can just write `{onclick}`.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\nFor usage details, check out [the `html!` guide](concepts/html/introduction.mdx).\n\n### Rendered\n\nThe `rendered` component lifecycle method is called once `view` has been called and Yew has rendered\nthe results to the DOM, but before the browser refreshes the page. This method is useful when you\nwant to perform actions that can only be completed after the component has rendered elements. There\nis also a parameter called `first_render` which can be used to determine whether this function is\nbeing called on the first render, or instead a subsequent one.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nNote that this lifecycle method does not require an implementation and will do nothing by default.\n:::\n\n### Update\n\nCommunication with components happens primarily through messages which are handled by the\n`update` lifecycle method. This allows the component to update itself\nbased on what the message was, and determine if it needs to re-render itself. Messages can be sent\nby event listeners, child components, Agents, Services, or Futures.\n\nHere's an example of what an implementation of `update` could look like:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nComponents may be re-rendered by their parents. When this happens, they could receive new properties\nand need to re-render. This design facilitates parent to child component communication by just\nchanging the values of a property. There is a default implementation which re-renders the component\nwhen props are changed.\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods, but are only caused when trying to update\nthe same component after every render when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it's often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nProperties enable child and parent components to communicate with each other.\nEvery component has an associated properties type which describes what is passed down from the parent.\nIn theory this can be any type that implements the `Properties` trait, but in practice there's no\nreason for it to be anything but a struct where each field represents a property.\n\n## Derive macro\n\nInstead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to\nautomatically generate the implementation instead.\nTypes for which you derive `Properties` must also implement `PartialEq`.\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they're set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: 'Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` keyword can be used inside of any HTML element or component to get the DOM `Element` that\nthe item is attached to. This can be used to make changes to the DOM outside of the `view` lifecycle\nmethod.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\nThe syntax is:\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components are able to create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function doesn't do anything.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/agents.mdx",
    "content": "---\ntitle: 'Agents'\ndescription: \"Yew's Actor System\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nAgents are a way to offload tasks to web workers.\n\nIn order for agents to run concurrently, Yew uses\n[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).\n\n## Lifecycle\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## Types of Agents\n\n### Reaches\n\n- Public - There will exist at most one instance of a Public Agent at any given time. Bridges will\n  spawn or connect to an already spawned agent in a web worker.\n  When no bridges are connected to this agent, the agent will disappear.\n\n- Private - Spawn a new agent in a web worker for every new bridge. This is good for moving shared but\n  independent behavior that communicates with the browser out of components. When\n  the connected bridge is dropped, the agent will disappear.\n\n- Global \\(WIP\\)\n\n## Communication between Agents and Components\n\n### Bridges\n\nA bridge allows bi-directional communication between an agent and a component. Bridges also allow agents to communicate with one another.\n\nA `use_bridge` hook is also provided to create bridges in a function component.\n\n### Dispatchers\n\nA dispatcher allows uni-directional communication between a component and an agent. A dispatcher allows a component to send messages to an agent.\n\n## Overhead\n\nAgents use web workers \\(i.e. Private and Public\\). They incur a serialization overhead on the\nmessages they send and receive. Agents use [bincode](https://github.com/servo/bincode) to communicate\nwith other threads, so the cost is substantially higher than just calling a function.\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/web_worker_fib) example shows how\n  components can send message to and receive message from agents.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'CSS with classes!'\ndescription: 'A handy macro to handle classes'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease in the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew does not natively provide a css in rust solution, but helps with styling by providing\nprogrammatic ways to interact with the html `class` attribute.\n\n## Classes\n\nThe `classes!` macro and associated `Classes` struct simplify the use of HTML classes:\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\nWe will expand upon this concept in [more CSS](../../more/css).\n\n## Inline Styles\n\nCurrently Yew does not provide any special help with inline styles specified via the `styles` attribute,\nbut you can use it like any other html attribute:\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\nWe will expand upon this concept in [more CSS](../../more/css).\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'HTML with html!'\ndescription: 'Its HTML but not quite!'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease in the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYou can write expressions resembling HTML with the `html!` macro. Behind the scenes Yew turns\nit into rust code representing the DOM to generate.\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nSimilar to format expressions, there is an easy way to embed values from the surrounding\ncontext into the html by applying curly brackets:\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\nOne major rule comes with the use of `html!` - you can only return 1 wrapping node.\nTo render a list of multiple elements, `html!` allows fragments. Fragments are tags\nwithout a name, that produce no html element by themselves.\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// error: only one root html element allowed\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// fixed: using html fragments\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\nWe will introduce Yew and HTML further in depth in [more HTML](concepts/html/introduction.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JS with RS'\ndescription: 'Javascript with Rust'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease in the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files, while also keeping the underlying technology\n> accessible where necessary.\n\nAs of today, WebAssembly is not feature-complete for DOM interactions. This means even in Yew we\nsometimes rely on calling Javascript. What follows is an overview of the involved libraries.\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool that enables calls to javascript from rust and back to rust from javascript.\n\nWe highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./wasm-bindgen.mdx).\n\n## web-sys\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs and allows us to write Javascript code in a rustyfied and safe way.\n\nExample:\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\nOnce again we highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./web-sys.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool to facilitate\nhigh-level interactions between Wasm modules and JavaScript; it is built with Rust by\n[The Rust and WebAssembly Working Group](https://rustwasm.github.io/).\n\nYew uses `wasm-bindgen` to interact with the browser through a number of crates:\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nThis section will explore some of these crates in a high level in order to make it easier to understand\nand use `wasm-bindgen` APIs with Yew. For a more in-depth guide to `wasm-bindgen` and its associated\ncrates then check out [The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/).\n\nFor documentation on the above crates check out [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html).\n\n:::tip\nUse the `wasm-bindgen` doc.rs search to find browser APIs and JavaScript types that have been imported\nover using `wasm-bindgen`.\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nThis crate provides many of the building blocks for the rest of the crates above. In this section we\nare only going to cover two main areas of the `wasm-bindgen` crate and that is the macro and some\ntypes / traits you will see pop up again and again.\n\n### `#[wasm_bindgen]` macro\n\nThe `#[wasm_bindgen]` macro provides an interface between Rust and JavaScript, providing a system\nfor translating between the two. Using this macro is more advanced, and you shouldn't need to reach\nfor it unless you are trying to use an external JavaScript library. The `js-sys` and `web-sys`\ncrates expose `wasm-bindgen` definitions for built-in Javascript types and browser APIs.\n\nLet's go over a simple example of using the `#[wasm-bindgen]` macro to import some specific flavours\nof the [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) function.\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// First up let's take a look of binding `console.log` manually, without the\n// help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations\n// manually ourselves, and the correctness of our program relies on the\n// correctness of these annotations!\n#[wasm_bindgen]\nextern \"C\" {\n\n    // Use `js_namespace` here to bind `console.log(..)` instead of just\n    // `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // The `console.log` is quite polymorphic, so we can bind it with multiple\n    // signatures. Note that we need to use `js_name` to ensure we always call\n    // `log` in JS.\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // Multiple arguments too!\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// using the imported functions!\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_This example was adapted from [1.2 Using console.log of The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html)_.\n\n### Simulating inheritance\n\nInheritance between JavaScript classes is a core feature of the Javascript language, and the DOM\n(Document Object Model) is designed around it. When types are imported using `wasm-bindgen` you can\nalso add attributes that describe their inheritance.\n\nIn Rust this inheritance is represented using the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\nand [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) traits. An example of this\nmight help; so say you have three types `A`, `B`, and `C` where `C` extends `B` which in turn\nextends `A`.\n\nWhen importing these types the `#[wasm-bindgen]` macro will implement the `Deref` and `AsRef`\ntraits in the following way:\n\n- `C` can `Deref` to `B`\n- `B` can `Deref` to `A`\n- `C` can be `AsRef` to `B`\n- Both `C` & `B` can be `AsRef` to `A`\n\nThese implementations allow you to call a method from `A` on an instance of `C` and to use `C` as if\nit was `&B` or `&A`.\n\nIts important to note that every single type imported using `#[wasm-bindgen]` has the same root type,\nyou can think of it as the `A` in the example above, this type is [`JsValue`](#jsvalue) which has\nits own section below.\n\n_[extends section in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) {#jsvalue}\n\nThis is a representation of an object owned by JavaScript, this is a root catch-all type for `wasm-bindgen`.\nAny type that comes from `wasm-bindgen` is a `JsValue` and this is because JavaScript doesn't have\na strong type system so any function that accepts a variable `x` doesn't define its type so `x` can be\na valid JavaScript value; hence `JsValue`. If you are working with imported functions or types that\naccept a `JsValue`, then any imported value is _technically_ valid.\n\n`JsValue` can be accepted by a function but that function may still only accept certain types and this\ncan lead to panics - so when using raw `wasm-bindgen` APIs check the documentation of the JavaScript\nbeing imported as to whether an exception (panic) will be raised if that value is not a certain type.\n\n_[`JsValue` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)._\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) {#JsCast}\n\nRust has a strong type system and JavaScript...doesn't 😞. In order for Rust to maintain these\nstrong types but still be convenient the WebAssembly group came up with a pretty neat trait `JsCast`.\nIts job is to help you move from one JavaScript \"type\" to another, which sounds vague, but it means\nthat if you have one type which you know is really another then you can use the functions of `JsCast`\nto jump from one type to the other. It's a nice trait to get to know when working with `web-sys`,\n`wasm_bindgen`, `js-sys` - you'll notice lots of types will implement `JsCast` from those crates.\n\n`JsCast` provides both checked and unchecked methods of casting - so that at runtime if you are\nunsure what type a certain object is you can try to cast it which returns possible failure types like\n[`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) and\n[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).\n\nA common example of this in [`web-sys`](./web-sys.mdx) is when you are trying to get the\ntarget of an event, you might know what the target element is but the\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API will always return an [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)\nso you will need to cast it to the element type. so you can call its methods.\n\n```rust\n// need to import the trait.\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // maybe the target is a select element?\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // do something amazing here\n        return;\n    }\n\n    // if it wasn't a select element then I KNOW it's a input element!\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\nThe [`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref)\nmethod is a checked cast that returns an `Option<&T>` which means the original type\ncan be used again if the cast failed and thus returned `None`. The\n[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nmethod will consume `self`, as per convention for into methods in Rust, and the type returned is\n`Result<T, Self>`. If the casting fails, the original `Self` value is returned in `Err`. You can try again\nor do something else with the original type.\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\nThe `Closure` type provides a way to transfer Rust closures to JavaScript, the closures passed to\nJavaScript must have a `'static` lifetime for soundness reasons.\n\nThis type is a \"handle\" in the sense that whenever it is dropped it will invalidate the JS\nclosure that it refers to. Any usage of the closure in JS after the Closure has been dropped will\nraise an exception.\n\n`Closure` is often used when you are working with a `js-sys` or `web-sys` API that accepts a type\n[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html).\nAn example of using a `Closure` in Yew can be found in the [Using `Closure` section](../html/events.mdx#using-closure-verbose)\non the [Events](../html/events.mdx) page.\n\n_[`Closure` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\nThe `js-sys` crate provides bindings / imports of JavaScript's standard, built-in objects, including\ntheir methods and properties.\n\nThis does not include any web APIs as this is what [`web-sys`](./web-sys.mdx) is for!\n\n_[`js-sys` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\nThe `wasm-bindgen-futures` crate provides a bridge for working with JavaScript Promise types as a\nRust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html), and contains\nutilities to turn a rust Future into a JavaScript Promise. This can be useful when working with\nasynchronous or otherwise blocking work in Rust (wasm), and provides the ability to interoperate\nwith JavaScript events and JavaScript I/O primitives.\n\nThere are three main interfaces in this crate currently:\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   A type that is constructed with a [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html)\n   and can then be used as a `Future<Output=Result<JsValue, JsValue>>`. This Rust future will resolve\n   or reject with the value coming out of the `Promise`.\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Converts a Rust `Future<Output=Result<JsValue, JsValue>>` into a\n   JavaScript `Promise`. The future’s result will translate to either a resolved or rejected\n   `Promise` in JavaScript.\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   Spawns a `Future<Output = ()>` on the current thread. This is the best way\n   to run a Future in Rust without sending it to JavaScript.\n\n_[`wasm-bindgen-futures` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` is going to be the most commonly used part of the `wasm-bindgen-futures` crate in Yew\nas this helps when using libraries that have async APIs.\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // console log \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew has also added support for futures in certain APIs, most notably you can create a\n`callback_future` which accepts an `async` block - this uses `spawn_local` internally.\n\n_[`spawn_local` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'The web-sys crate provides bindings for Web APIs.'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs. This is\nprocedurally generated from browser WebIDL which is why some names are so long and why some types are vague.\n\n## Features in `web-sys`\n\nThe `web-sys` crate with all of it's features enabled can add lots of bloat to a Wasm application,\nin order to get around this issue most types are feature gated so that you only include the types\nyou require for your application. Yew includes a number of features from `web-sys` and\nexposes some types in it's public API, you will often need to add `web-sys` as a dependency yourself.\n\n## Inheritance in `web-sys`\n\nIn the [Simulating inheritance section](./wasm-bindgen.mdx#simulating-inheritance) you can read how in\ngeneral Rust provides an approach to simulate inheritance in JavaScript. This is very important in\n`web-sys` as understanding what methods are available on a type means understanding it's inheritance.\n\nThis section is going to look at a specific element and list out it's inheritance using Rust by\ncalling [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) until\nthe value is [`JsValue`](./wasm-bindgen.mdx#jsvalue):\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement is <textarea> in html.\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // Notice we've moved from web-sys types now into built-in\n    // JavaScript types which are in the js-sys crate.\n    let object: &js_sys::Object = event_target.deref();\n\n    // Notice we've moved from js-sys type to the root JsValue from\n    // the wasm-bindgen crate.\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // Using deref like this means we have to manually traverse\n    // the inheritance tree, however, you can call JsValue methods\n    // on the HtmlTextAreaElement type.\n    // The `is_string` method comes from JsValue.\n    assert!(!text_area.is_string());\n\n    // empty function just to prove we can pass HtmlTextAreaElement as a\n    // &EventTarget.\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // The compiler will walk down the deref chain in order to match the types here.\n    this_function_only_takes_event_targets(&text_area);\n\n    // The AsRef implementations allow you to treat the HtmlTextAreaElement\n    // as an &EventTarget.\n\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[Inheritance in `web-sys` in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)._\n\n## The `Node` in `NodeRef`\n\nYew uses a [`NodeRef`](concepts/function-components/node-refs.mdx) in order to provide a way for keeping a reference to\na `Node` made by the [`html!`](concepts/html/introduction.mdx) macro. The `Node` part of `NodeRef` is referring to\n[`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html). The\n`NodeRef::get` method will return a `Option<Node>` value, however, most of the time in Yew you want\nto cast this value to a specific element so you can use it's specific methods. This casting\ncan be done using [`JsCast`](./wasm-bindgen.mdx#JsCast) on the `Node` value, if present, but Yew\nprovides the `NodeRef::cast` method to perform this casting for convenience and so that you don't\nnecessarily have to include the `wasm-bindgen` dependency for the `JsCast` trait.\n\nThe two code blocks below do essentially the same thing, the first is using `NodeRef::cast` and\nthe second is using [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\non the `web_sys::Node` returned from `NodeRef::get`.\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript example to Rust\n\nThis section is to help show that any examples that use JavaScript to interact with the Web APIs\ncan be adapted and written using Rust with `web-sys`.\n\n### JavaScript example\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e = Mouse event.\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left //x position within the element.\n    var y = e.clientY - rect.top //y position within the element.\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` example\n\nUsing `web-sys` alone the above JavaScript example could be implemented like this:\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable all the web-sys features we want to use!\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// we now need to save the `mousemove` Closure so that when\n// this event fires the closure is still in memory.\n```\n\nThis version is much more verbose, but you will probably notice part of that is because of failure\ntypes reminding us that some of these function calls have invariants that must be held otherwise will\ncause a panic in Rust. Another part of the verbosity is the calls to `JsCast` in order to cast into\ndifferent types so that you can call it's specific methods.\n\n### Yew example\n\nIn Yew you will mostly be creating [`Callback`](concepts/function-components/callbacks.mdx)s to use in the\n[`html!`](concepts/html/introduction.mdx) macro so the example is going to use this approach instead of completely copying\nthe approach above:\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable the `DomRect` feature in order to use the\n# `get_bounding_client_rect` method.\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## External libraries\n\n`web-sys` is a raw binding to the Web API so it comes with some pain in Rust because it was not\ndesigned with Rust or even a strong type system in mind, this is where community crates come in to\nprovide abstractions over `web-sys` to provide more idiomatic Rust APIs.\n\n_[External libraries page](/community/external-libs)_\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solve this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from parent to a child.\nThey become cumbersome to pass down through deeply nested component tree or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components in order to reach the component needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Children, Component, Context, Html, Properties, function_component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[function_component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Children,\n}\n\n#[function_component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[function_component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[function_component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct is used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[function_component]\nfn NavButton() -> Html {\n    let theme = use_context::<Rc<Theme>>().expect(\"Context not found\");\n\n    html! {\n        // use theme\n    }\n}\n\n#[function_component]\nfn App() -> Html {\n    let theme = use_memo(|_| Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    }, ());\n\n    html! {\n        <ContextProvider<Rc<Theme>> context={theme}>\n            <NavButton />\n        </ContextProvider<Rc<Theme>>>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, it's likely that context will help you.\nHere's some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the current logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, doesn't mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component which takes `articles` as prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating context value a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nIn order to mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/contexts)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\nCallbacks are used to asynchronously communicate upwards the components tree and with other things like agents or the DOM during event handling.\nInternally their type is just an `Fn` wrapped in `Rc` to allow them to be cheaply cloned.\n\nThey have an `emit` function if you want to call them manually.\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\")); // call the callback\n// web_sys::console::log_1(&result.into()); // if uncommented will print \"Bye Bob\"\n```\n\n## Passing callbacks as props\n\nA common pattern in yew is to create a callback and pass it down as a prop.\n\n```rust\nuse yew::{function_component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// Then supply the prop\n#[function_component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM Events and Callbacks\n\nCallbacks are also used to hook into DOM events.\n\nFor example here we define a callback that will be called when the user clicks the button:\n\n```rust\nuse yew::{function_component, html, Html, Properties, Callback};\n\n#[function_component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.\n\n```rust\nuse yew::{function_component, html, Html, Properties, Children};\n\n#[function_component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Children, // the field name `children` is important!\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n    // highlight-next-line\n            { for props.children.iter() } // you can forward children like this\n        </div>\n    }\n}\n```\n\n## Further reading\n\n- [Advanced ways to handle children](../../advanced-topics/children)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'Communication between components'\n---\n\n## Parent to child messaging\n\nPass data as [props](./properties) that cause a rerender, this is the way to pass messages to children.\n\n## Child to parent messaging\n\nPass down a callback via props, that the child on an event can call. [Example](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'Generic Components'\ndescription: 'The #[function_component] attribute'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `#[function_component]` attribute also works with generic functions for creating generic components.\n\n```rust\nuse std::fmt::Display;\nuse yew::{function_component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[function_component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Display,\n{\n    html! {\n        <p>\n            { &props.data }\n        </p>\n    }\n}\n\n// then can be used like this\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// or\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'Custom Hooks'\n---\n\n## Defining custom Hooks\n\nComponent's stateful logic can be extracted into reusable function by creating custom Hooks.\n\nConsider that we wish to create an event listener that listens to an event on the `window`\nobject.\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[function_component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nThere's one problem with this code: the logic can't be reused by another component.\nIf we build another component which keeps track of the an event,\ninstead of copying the code, we can move the logic into a custom hook.\n\nWe'll start by creating a new function called `use_event`.\nThe `use_` prefix denotes that a function is a hook.\nThis function will take an event target, an event type and a callback.\nAll hooks must be marked by `#[hook]` to function as hook.\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nThis is a simple hook which can be created by composing built-in hooks. For this example, we'll use the\n`use_effect_with_deps` hook, so an event listener can be recreated when the hook arguments change.\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with_deps(\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n        deps,\n    );\n}\n```\n\nAlthough this approach works in almost all cases, it can't be used to write primitive hooks like the pre-defined hooks we've been using already.\n\nView the docs on [docs.rs](https://docs.rs/yew) for documentation and `hooks` directory to see implementations of pre-defined hooks.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks are functions that let you store state and perform side-effects.\n\nYew comes with a few pre-defined Hooks. You can also create your own or discover many [community made hooks](/community/awesome#hooks).\n\n## Rules of hooks\n\n1. A hook function name always has to start with `use_`\n2. Hooks can only be used in the following locations:\n    - Top level of a function / hook.\n    - Blocks inside a function / hook, given it's not already branched.\n    - In the condition of a top level `if` expression inside a function / hook.\n    - In the scrutinee of a top level `match` expression inside a function / hook.\n3. Hooks must be called in the same order for every render. Returning early is only allowed when using [Suspense](../../suspense.mdx)\n\nThese rules are enforced by either compile time or run-time errors.\n\n### Pre-defined Hooks\n\nYew comes with the following predefined Hooks:\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with_deps`\n- `use_context`\n- `use_force_update`\n\nThe documentation for these hooks can be found in the [Yew API docs](https://docs.rs/yew/0.20.0/yew/functional/index.html)\n\n### Custom Hooks\n\nThere are cases where you want to define your own Hooks to encapsulate potentially stateful logic from a component into reusable functions.\nSee the [Defining custom hooks](concepts/function-components/hooks/custom-hooks.mdx#defining-custom-hooks) section for more information.\n\n## Further reading\n\n- The React documentation has a section on [React hooks](https://reactjs.org/docs/hooks-intro.html).\n  These are not exactly the same as Yew's hooks, but the underlying concept is similar.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLets revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behaviour of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavours of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[function_component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{function_component, html, Html};\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[function_component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes `Html` is just an alias for `VNode` - virtual node.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'Node Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` attribute can be used to attach the `NodeRef` to an HTML element. In callbacks,\nyou can then get the DOM `Element` that the ref is attached to. This can be used to make\nchanges to the DOM outside of the `view` lifecycle method, retrieve the value of an `<input>`\nand other direct interactions with the DOM via the javascript API.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\n\n:::caution\nDo not manually modify the DOM tree that is rendered by Yew. Treat the `NodeRef` as a read-only\naccess, if you are unsure.\n:::\n\n## Further Reading\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` example](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nProperties are often shortened as \"Props\".\n\n:::\n\nProperties are essentially component arguments that Yew can keep watch on.\n\nA type has to implement the `Properties` trait before it can be used as the properties of a component.\n\n## Reactivity\n\nYew checks if props have changed when reconciling the vdom during rerendering, to know if nested components needs to be rerendered.\nThis way Yew can be considered a very reactive framework as changes from the parent will always be propagated downwards\nand the view will never be out of sync from the data coming from props/state.\n\n:::tip\n\nIf you have not yet completed the [tutorial](../../tutorial), try it out and test this reactivity yourself!\n\n:::\n\n## Derive macro\n\nYew provides a derive macro to easily implement the `Properties` trait on structs.\n\nTypes for which you derive `Properties` must also implement `PartialEq` so Yew can do data comparison.\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## Use in function components\n\nThe attribute `#[function_component]` allows to optionally receive Props in the function arguments. To supply them,\nthey are assigned via attributes in the `html!` macro.\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{props.is_loading.clone()}</> }\n}\n\n// Then supply the prop\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{function_component, html, Html};\n\n\n\n\n\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// No props to supply\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld />}\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## Derive macro field attributes\n\nWhen deriving `Properties` all fields are required by default.\nThe following attributes allow you to give your props default values which will be used when parent has not set them.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading.clone() {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// Then use like this with default\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// Or no override the default\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`. The expression\nis evaluated when the properties are constructed and no explicit value has been given.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or(\"Bob\".to_string())]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// Then use like this with default\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// Or no override the default\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\nThe function is called when no explicit value has been given for that attribute.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\nfn create_default_name() -> String {\n    \"Bob\".to_string()\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// Then use like this with default\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// Or no override the default\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a shared pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or(AttrValue::from(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n#[function_component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = props! {\n        Props {} // Notice we did not need to specify name prop\n    };\n    // highlight-end\n    html! {<HelloWorld ..pre_made_props />}\n}\n```\n\n## Evaluation Order\n\nProps are evaluated in the order they're specified, as shown by the following example:\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## Anti Patterns\n\nWhile almost any Rust type can be passed as properties, there are some anti-patterns that should be avoided.\nThese include, but are not limited to:\n\n1. Using `String` type instead of `AttrValue`. <br />\n   **Why is this bad?** `String` can be expensive to clone.\n   Cloning is often needed when the prop value is used with hooks and callbacks. `AttrValue` is either\n   a reference-counted string (`Rc<str>`) or a `&'static str`, thus very cheap to clone.<br />\n   **Note**: `AttrValue` internally is `IString` from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n2. Using interior mutability. <br />\n   **Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should\n   _generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when state has changed)\n   so you may have to manually force a render. Like all things, it has its place. Use it with caution.\n3. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue\n   or PR a fix to this documentation.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: 'Pure Components'\n---\n\nA function component is considered [pure] when the returned `Html` is deterministically derived\nfrom its props, and its view function mutates no state or has other side-effects.\n\n[pure]: https://en.wikipedia.org/wiki/Pure_function\n\nFor example below is a pure component. For a given prop `is_loading` it will always result in the same `Html` without any side effects.\n\n```rust\nuse yew::{Properties, function_component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\nIf you have an internal pure component that makes no use of hooks and other component machinery, you can often write it instead\nas a normal function returning `Html` and avoid a bit of overhead for Yew, related to running the component lifecycle. Use\n[expression syntax](concepts/html/literals-and-expressions.mdx#expressions) to render them in `html!`.\n:::\n\n## Impure components\n\nYou might wonder if a component can be impure if it does not use any globals, since its just a function that is called every render.\nThis is where the next topic comes in - [hooks](./hooks)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/function-components/state.mdx",
    "content": "---\ntitle: 'State'\n---\n\n## General view of how to store state\n\nThis table can be used as a guide when deciding what state storing type fits best for your use case:\n\n| Hook                     | Type                       | Rerender when?               | Scope               |\n| ------------------------ | -------------------------- | ---------------------------- | ------------------- |\n| [use_state]              | `T`                        | got set                      | component instance  |\n| [use_state_eq]           | `T: PartialEq`             | got set with diff. value     | component instance  |\n| [use_reducer]            | `T: Reducible`             | got reduced                  | component instance  |\n| [use_reducer_eq]         | `T: Reducible + PartialEq` | got reduced with diff. value | component instance  |\n| [use_memo]               | `Deps -> T`                | dependencies changed         | component instance  |\n| [use_callback]           | `Deps -> Callback<E>`      | dependencies changed         | component instance  |\n| [use_mut_ref]            | `T`                        | -                            | component instance  |\n| a static global variable | `T`                        | -                            | global, used by all |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/classes.mdx",
    "content": "---\ntitle: 'Classes'\ndescription: 'A handy macro to handle classes'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Classes\n\nThe struct `Classes` can be used to deal with HTML classes.\n\nWhen pushing a string to the set, `Classes` ensures that there is one element\nfor every class even if a single string might contain multiple classes.\n\n`Classes` can also be merged by using `Extend` (i.e.\n`classes1.extend(classes2)`) or `push()` (i.e. `classes1.push(classes2)`). In\nfact, anything that implements `Into<Classes>` can be used to push new classes\nto the set.\n\nThe macro `classes!` is a convenient macro that creates one single `Classes`.\nIts input accepts a comma separated list of expressions. The only requirement\nis that every expression implements `Into<Classes>`.\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = [\"class-1\", \"class-2\"];\n\nhtml! {\n  <div class={classes!(my_classes.as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Components that accept classes\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Children,\n}\n\n#[function_component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/components.mdx",
    "content": "---\ntitle: 'Components'\ndescription: 'Create complex layouts with component hierarchies'\n---\n\n## Basic\n\nComponents can be used in the `html!` macro:\n\n```rust\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[function_component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // With the whole set of props provided at once\n        <MyComponentWithProps ..props.clone() />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## Nested\n\nComponents can be passed children if they have a `children` field in their `Properties`.\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Children,\n}\n\n#[function_component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\nThe `html!` macro allows you to pass a base expression with the `..props` syntax instead of specifying each property individually,\nsimilar to Rust's [Functional Update Syntax](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax).\nThis base expression must occur after any individual props are passed.\nWhen passing a base props expression with a `children` field, the children passed in the `html!` macro overwrite the ones already present in the props.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Children,\n}\n\n#[function_component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Children::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // props.children will be overwritten with this\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children. In the following example, the `List` component can wrap `ListItem` components. For a real world example of this pattern, check out the `yew-router` source code. For a more advanced example, check out the `nested-list` example in the main yew repository.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[function_component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[function_component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n## Relevant examples\n\n- [Function Todo MVC](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/function_todomvc)\n- [Function Router](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/function_router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: 'Conditional rendering'\ndescription: 'Rendering nodes conditionally in html!'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If blocks\n\nTo conditionally render some markup, we wrap it in an `if` block:\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/elements.mdx",
    "content": "---\ntitle: 'Elements'\ndescription: 'Both HTML and SVG elements are supported'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM nodes\n\nThere are many reasons why you might want to create or manage DOM nodes manually in Yew, such as\nwhen integrating with JS libraries that can cause conflicts with managed components.\n\nUsing `web-sys`, you can create DOM elements and convert them into a `Node` - which can then be\nused as a `Html` value using `VRef`:\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[function_component]\nfn MyComponent() -> Html {\n    // memoize as this only needs to be executed once\n    let node = use_memo(\n        |_| {\n            // Create a div element from the document\n            let div: Element = document().create_element(\"div\").unwrap();\n            // Add content, classes etc.\n            div.set_inner_html(\"Hello, World!\");\n            // Convert Element into a Node\n            let node: Node = div.into();\n            // Return that Node as a Html value\n            Html::VRef(node)\n        },\n        (),\n    );\n\n    // use_memo return Rc so we need to deref and clone\n    (*node).clone()\n}\n\n```\n\n## Dynamic tag names\n\nWhen building a higher-order component you might find yourself in a situation where the element's tag name isn't static.\nFor example, you might have a `Title` component which can render anything from `h1` to `h6` depending on a level prop.\nInstead of having to use a big match expression, Yew allows you to set the tag name dynamically\nusing `@{name}` where `name` can be any expression that returns a string.\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## Boolean Attributes\n\nSome content attributes (e.g checked, hidden, required) are called boolean attributes. In Yew,\nboolean attributes need to be set to a bool value:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nThis will result in **HTML** that's functionally equivalent to this:\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\nSetting a boolean attribute to false is equivalent to not using the attribute at all; values from\nboolean expressions can be used:\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nThis will result in the following **HTML**:\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## String-like attributes\n\nBut apart from a select few boolean attributes, you will probably be dealing with a lot of string-like HTML attributes and Yew has a few option for those\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nThey are all valid **but** we encourage you to favor Yew's custom `AttrValue`, especially if you need to clone or pass them as properties to another component.\n\n## Optional attributes for HTML elements\n\nMost HTML attributes can use optional values (Some(x) or None). This allows us to omit the attribute if the attribute is marked as optional.\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\nIf the attribute is set to `None`, the attribute won't be set in the DOM.\n\n## Relevant examples\n\n- [Inner HTML](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/inner_html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/events.mdx",
    "content": "---\ntitle: 'Events'\n---\n\n## Introduction\n\nYew integrates with the [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate and\nuses the events from that crate. The [table below](#event-types) lists all of the `web-sys`\nevents that are accepted in the `html!` macro.\n\nYou can still add a [`Callback`](../function-components/callbacks.mdx) for an event that is not listed in the table\nbelow, see [Manual event listener](#manual-event-listener).\n\n## Event Types\n\n:::tip\nAll the event types mentioned in the following table are re-exported under `yew::events`.\nUsing the types from `yew::events` makes it easier to ensure version compatibility than\nif you were to manually include `web-sys` as a dependency in your crate because you won't\nend up using a version which conflicts with the version that Yew specifies.\n:::\n\nThe event listener name is the expected name when adding an event `Callback` in the `html` macro:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nThe event name is the listener without the \"on\" prefix, therefore, the `onclick` event listener\nlistens for `click` events. See the end of this page for a [full list of available event](#available-events) with their types.\n\n## Event bubbling {#event-bubbling}\n\nEvents dispatched by Yew follow the virtual DOM hierarchy when bubbling up to listeners. Currently, only the bubbling phase\nis supported for listeners. Note that the virtual DOM hierarchy is most often, but not always, identical to the actual\nDOM hierarchy. The distinction is important when working with [portals](../../advanced-topics/portals) and other\nmore advanced techniques. The intuition for well implemented components should be that events bubble from children\nto parents, so that the hierarchy in your coded `html!` is the one observed by event handlers.\n\nIf you are not interested in event bubbling, you can turn it off by calling\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n_before_ starting your app. This speeds up event handling, but some components may break from not receiving events they expect.\nUse this with care!\n\n## Event delegation\n\nIt can be surprising that event listeners are _not_ directly registered on the element where they are rendered. Instead, events\nare delegated from the subtree root of the Yew app. Still, events are delivered in their native form, and no synthetic\nform is created. This can lead to mismatches between the event you'd expect in html listeners and those showing up in Yew.\n\n- [`Event::current_target`] points to the Yew subtree root instead of the element the listener is added on. Use\n  [`NodeRef`](../function-components/node-refs.mdx) if you want access to the underlying `HtmlElement`.\n- [`Event::event_phase`] is always [`Event::CAPTURING_PHASE`]. Internally, the event will behave as if it was in the bubbling\n  phase, the event propagation is replayed and the event [bubbles _up_](#event-bubbling), i.e. event listeners higher up in\n  the virtual DOM will trigger _after_ event listeners below them. Currently, capturing listeners are not supported by Yew.\n\n    This also means that events registered by Yew will usually fire before other event listeners.\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## Typed event target\n\n:::caution\nIn this section **target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))**\nis always referring to the element at which the event was dispatched from.\n\nThis will **not** always be the element at which the `Callback` is placed.\n:::\n\nIn event `Callback`s you may want to get the target of that event. For example, the\n`change` event gives no information but is used to notify that something has changed.\n\nIn Yew getting the target element in the correct type can be done in a few ways and we will go through\nthem here. Calling [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)\non an event returns an optional [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html)\ntype, which might not seem very useful when you want to know the value of your input element.\n\nIn all the approaches below we are going to tackle the same problem, so it's clear where the approach\ndiffers opposed to the problem at hand.\n\n**The Problem:**\n\nWe have an `onchange` `Callback` on my `<input>` element and each time it is invoked we want to send\nan [update](components#update) `Msg` to our component.\n\nOur `Msg` enum looks like this:\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### Using `JsCast`\n\nThe [`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate has\na useful trait; [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nwhich allows us to hop and skip our way to the type we want, as long as it implements `JsCast`. We can\ndo this cautiously, which involves some runtime checks and failure types like `Option` and `Result`,\nor we can do it dangerously.\n\nEnough talk, more code:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# need wasm-bindgen for JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // When events are created the target is undefined, it's only\n            // when dispatched does the target get added.\n            let target: Option<EventTarget> = e.target();\n            // Events can bubble so this listener might catch events from child\n            // elements which are not of type HtmlInputElement\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        // Here we are sure that this is input element so we can convert it to the appropriate type without checking\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nThe methods from `JsCast` are [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nand [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)\nand you can probably see, they allowed\nus to go from `EventTarget` to [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html).\nThe `dyn_into` method is cautious because at\nruntime it will check whether the type is actually a `HtmlInputElement` and if not return an\n`Err(JsValue)`, the [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\nis a catch-all type and is essentially giving you back the object to try again.\n\nAt this point you might be thinking... when is the dangerous version ok to use? In the case above it\nis safe<sup>1</sup> as we've set the `Callback` on to an element with no children so the target can\nonly be that same element.\n\n_<sup>1</sup> As safe as anything can be when JS land is involved._\n\n### Using `TargetCast`\n\n**It is highly recommended to read [Using JsCast](#using-jscast) first!**\n\n:::note\n`TargetCast` was designed to feel very similar to `JsCast` - this is to allow new users to get a feel\nfor the behaviour of `JsCast` but with the smaller scope of events and their targets.\n\n`TargetCast` vs `JsCast` is purely preference, you will find that `TargetCast` implements something\nsimilar to what you would using `JsCast`.\n:::\n\nThe `TargetCast` trait is built on top of `JsCast` and is specialized towards getting typed event\ntargets from events.\n\n`TargetCast` comes with Yew so no need to add a dependency in order to use the trait methods on events\nbut it works in a very similar way to `JsCast`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nIf you followed the advice above and read about `JsCast`, or know the trait, you can probably\nsee that `TargetCast::target_dyn_into` feels similar to `JsCast::dyn_into` but specifically\ndoes the cast on the target of the event. `TargetCast::target_unchecked_into` is similar to\n`JsCast::unchecked_into`, and as such all the same warnings above `JsCast` apply to `TargetCast`.\n\n### Using `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) can be used instead of querying the event given to a `Callback`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nUsing `NodeRef`, you can ignore the event and use the `NodeRef::cast` method to get an\n`Option<HtmlInputElement>` - this is optional as calling `cast` before the `NodeRef` has been\nset, or when the type doesn't match will return `None`.\n\nYou might also see by using `NodeRef` we don't have to send the `String` back into state as we always access to `input_node_ref` - so we could do the following:\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // do something with value\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nWhich approach you take depends on your component and your preferences, there is no _blessed_ way\nper se.\n\n## Manual event listener\n\nYou may want to listen to an event that is not supported by Yew's `html` macro, see the\n[supported events listed here](#event-types).\n\nIn order to add an event listener to one of elements manually we need the help of\n[`NodeRef`](../function-components/node-refs.mdx) so that in `use_effect_with_deps` we can add a listener using the\n[`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) and\n[wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API.\n\nThe examples below are going to show adding listeners for the made-up `custard` event. All events\neither unsupported by yew or custom can be represented as a\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html). If you\nneed to access a specific method or field on a custom / unsupported event then you can use the\nmethods of [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nin order to convert to the type required.\n\n### Using `Closure` (verbose)\n\nUsing the `web-sys` and `wasm-bindgen` API's directly for this can be a bit painful.. so brace\nyourself ([there is a more concise way thanks to `gloo`](#using-gloo-concise)).\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with_deps(\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        },\n        div_node_ref.clone()\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `Closures`, see\n[The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html).\n\n### Using `gloo` (concise)\n\nThe easier way is with `gloo`, more specifically [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)\nwhich is an abstraction for `web-sys`, `wasm-bindgen`.\n\n`gloo_events` has the `EventListener` type which can be used to create and store the\nevent listener.\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with_deps(\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        },\n        div_node_ref.clone()\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `EventListener`, see the\n[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html).\n\n## Full list of available events {#available-events}\n\n| Event listener name         | `web_sys` Event Type                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/fragments.mdx",
    "content": "---\ntitle: 'Fragments'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro always requires a single root node. In order to get around this restriction, you\ncan use an \"empty tag\" (these are also called \"fragments\").\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// error: only one root html element allowed\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'The procedural macro for generating HTML and SVG'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro allows you to write HTML and SVG code declaratively. It is similar to JSX\n(an extension to JavaScript which allows you to write HTML-like code inside of JavaScript).\n\n**Important notes**\n\n1. The `html!` macro only accepts one root html node (you can counteract this by using\n   [fragments](./fragments.mdx) or [iterators](./../html/lists.mdx))\n2. An empty `html! {}` invocation is valid and will not render anything\n3. Literals must always be quoted and wrapped in braces: `html! { <p>{ \"Hello, World\" }</p> }`\n4. The `html!` macro will make all tag names lower case. To use upper case characters (which are required for some SVG elements) use [dynamic tag names](concepts/html/elements.mdx#dynamic-tag-names): `html! { <@{\"myTag\"}></@> }`\n\n:::note\nThe `html!` macro can reach the default recursion limit of the compiler. If you encounter compilation errors,\nadd an attribute like `#![recursion_limit=\"1024\"]` in the crate root to overcome the problem.\n:::\n\n## Tag Structure\n\nTags are based on HTML tags. Components, Elements, and Lists are all based on this tag syntax.\n\nTags must either self-close `<... />` or have a corresponding end tag for each start tag.\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\nFor convenience, elements which _usually_ require a closing tag are **allowed** to self-close. For example, writing `html! { <div class=\"placeholder\" /> }` is valid.\n:::\n\n## Children\n\nCreate complex nested HTML and SVG layouts with ease:\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nIf you compile Yew using a nightly version of the Rust compiler, the macro will warn you about some\ncommon pitfalls that you might run into. Of course, you may need to use the stable compiler (e.g.\nyour organization might have a policy mandating it) for release builds, but even if you're using a\nstable toolchain, running `cargo +nightly check` might flag some ways that you could improve your\nHTML code.\n\nAt the moment the lints are mostly accessibility-related. If you have ideas for lints, please feel\nfree to [chime in on this issue](https://github.com/yewstack/yew/issues/1334).\n\n## Specifying attributes and properties\n\nAttributes are set on elements in the same way as in normal HTML:\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\nProperties are specified with `~` before the element name:\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\nThe braces around the value can be omitted if the value is a literal.\n\n:::\n\n:::note What classifies as a literal\n\nLiterals are all valid [literal expressions](https://doc.rust-lang.org/reference/expressions/literal-expr.html)\nin Rust. Note that [negative numbers are **not** literals](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)\nand thus must be enclosed in curly-braces `{-6}`\n\n:::\n\n:::note Component properties\nComponent properties are passed as Rust objects and are different from the element attributes/properties described here.\nRead more about them at [Component Properties](../function-components/properties.mdx)\n:::\n\n### Special properties\n\nThere are special properties which don't directly influence the DOM but instead act as instructions to Yew's virtual DOM.\nCurrently, there are two such special props: `ref` and `key`.\n\n`ref` allows you to access and manipulate the underlying DOM node directly. See [Refs](../function-components/node-refs.mdx) for more details.\n\n`key` on the other hand gives an element a unique identifier which Yew can use for optimization purposes.\n\n:::info\nRead more at [Lists](./html/lists)\n:::\n\n## Conditional Rendering\n\nMarkup can be rendered conditionally by using Rust's conditional structures. ' +\n'Currently only `if` and `if let` are supported.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\nRead more at [Conditional Rendering](./conditional-rendering.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/lists.mdx",
    "content": "---\ntitle: 'Lists'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Iterators\n\nYew supports two different syntaxes for building HTML from an iterator.\n\n<Tabs>\n  <TabItem value=\"Syntax type 1\" label=\"Syntax type 1\">\n\nThe first is to call `collect::<Html>()` on the final transform in your iterator, which returns a\nlist that Yew can display.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Syntax type 2\" label=\"Syntax type 2\">\n\nThe alternative is to use the `for` keyword, which is not native Rust syntax and instead is used by\nthe HTML macro to output the needed code to display the iterator.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Keyed lists\n\nA keyed list is an optimized list that has keys on **all** children.\n`key` is a special prop provided by Yew which gives an html element or component a unique identifier\nwhich is used for optimization purposes inside Yew.\n\n:::caution\nKey has to be unique only in each list, in contrast to the global uniqueness of html `id`s. It must not depend on the order of the list.\n:::\n\nIt is always recommended to add keys to lists.\n\nKeys can be added by passing a unique `String`, `str` or integer to the special `key` prop:\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### Performance increases\n\nWe have [Keyed list](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/keyed_list) example that lets you test the performance improvements, but here is rough rundown:\n\n1. Go to [Keyed list](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/keyed_list) hosted demo\n2. Add 500 elements.\n3. Disable keys.\n4. Reverse the list.\n5. Look at \"The last rendering took Xms\" (At the time of writing this it was ~60ms)\n6. Enable keys.\n7. Reverse the list.\n8. Look at \"The last rendering took Xms\" (At the time of writing this it was ~30ms)\n\nSo just at the time of writing this, for 500 components its a x2 increase of speed.\n\n### Detailed explanation\n\nUsually you just need a key on every list item when you iterate and the order of data can change.\nIt's used to speed up the reconciliation process when re-rendering the list.\n\nWithout keys, lets assume you iterate through `[\"bob\",\"sam\",\"rob\"]`, ending up with the html:\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\nThen on the next render, if your list changed to `[\"bob\",\"rob\"]`, yew could delete\nthe element with id=\"rob\" and update id=\"sam\" to be id=\"rob\"\n\nIf you had added a key to each element, the initial html would be the same, but after\nthe render with the modified list, `[\"bob\",\"rob\"]`, yew would just delete the second\nhtml element and leave the rest untouched since it can use the keys to associate them.\n\nIf you ever encounter a bug/\"feature\" where you switch from one component to another but both have a div as the highest rendered element.\nYew reuses the rendered html div in those cases as an optimization.\nIf you need that div to be recreated instead of reused, then you can add different keys and they wont be reused\n\n## Further reading\n\n- [TodoMVC](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/todomvc)\n- [Keyed list](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/keyed_list)\n- [Router](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'Literals and Expressions'\n---\n\n## Literals\n\nIf expressions resolve to types that implement `Display`, they will be converted to strings and inserted into the DOM as a [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) node.\n:::note\nString literals create `Text` nodes, which are treated as strings by the browser. Hence, even if the expression contains a `<script>` tag you can't fall for XSS and such security issues, unless of course you wrap the expression in a `<script>` block.\n:::\n\nAll display text must be enclosed by `{}` blocks because text is handled as an expression. This is\nthe largest deviation from normal HTML syntax that Yew makes.\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## Expressions\n\nYou can insert expressions in your HTML using `{}` blocks, as long as they resolve to `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\nIt often makes sense to extract these expressions into functions or closures to optimize for readability:\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/router.mdx",
    "content": "---\ntitle: 'Router'\ndescription: \"Yew's official router\"\n---\n\nRouters in Single Page Applications (SPA) handle displaying different pages depending on what the URL is. Instead of the\ndefault behavior of requesting a different remote resource when a link is clicked, the router instead sets the URL\nlocally to point to a valid route in your application. The router then detects this change and then decides what to\nrender.\n\nYew provides router support in the `yew-router` crate. To start using it, add the dependency to your `Cargo.toml`\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = \"0.17\"\n```\n\nThe utilities needed are provided under `yew_router::prelude`,\n\n## Usage\n\nYou start by defining a `Route`.\n\nRoutes are defined as an `enum` which derives `Routable`. This enum must be `Clone + PartialEq`.\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\nA `Route` is paired with a `<Switch />` component, which finds the variant whose path matches the browser's\ncurrent URL and passes it to the `render` callback. The callback then decides what to render. In case no path is\nmatched, the router navigates to the path with `not_found` attribute. If no route is specified, nothing is rendered, and\na message is logged to console stating that no route was matched.\n\nMost of yew-router's components, in particular `<Link />` and `<Switch />`, must be (grand-)children of one of the Router components\n(e.g. `<BrowserRouter />`). You usually only need a single Router in your app, most often rendered immediately by your most top-level `<App />`\ncomponent. The Router registers a context, which is needed for Links and Switches to function. An example is shown below.\n\n:::caution\nWhen using `yew-router` in browser environment, `<BrowserRouter />` is highly recommended.\nYou can find other router flavours in the [API Reference](https://docs.rs/yew-router/).\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[function_component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[function_component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### Path Segments\n\nIt is also possible to extract information from a route using dynamic and named wildcard segments.\nYou can then access the post's id inside `<Switch />` and forward it to the appropriate component via properties.\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\nYou can have a normal `Post` variant instead of `Post {id: String}` too. For example when `Post` is rendered\nwith another router, the field can then be redundant as the other router is able to match and handle the path. See the\n[Nested Router](#nested-router) section below for details\n:::\n\nNote the fields must implement `Clone + PartialEq` as part of the `Route` enum. They must also implement\n`std::fmt::Display` and `std::str::FromStr` for serialization and deserialization. Primitive types like integer, float,\nand String already satisfy the requirements.\n\nIn case when the form of the path matches, but the deserialization fails (as per `FromStr`). The router will consider\nthe route as unmatched and try to render the not found route (or a blank page if the not found route is unspecified).\n\nConsider this example:\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch function renders News and id as is. Omitted here.\n```\n\nWhen the segment goes over 255, `u8::from_str()` fails with `ParseIntError`, the router will then consider the route\nunmatched.\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\nFor more information about the route syntax and how to bind parameters, check\nout [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params).\n\n### Location\n\nThe router provides a universal `Location` struct via context which can be used to access routing information.\nThey can be retrieved by hooks or convenient functions on `ctx.link()`.\n\n### Navigation\n\n`yew_router` provides a handful of tools to work with navigation.\n\n#### Link\n\nA `<Link />` renders as an `<a>` element, the `onclick` event handler will call\n[preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault), and push the targeted page to the\nhistory and render the desired page, which is what should be expected from a Single Page App. The default onclick of a\nnormal anchor element would reload the page.\n\nThe `<Link />` component also passes its children to the `<a>` element. Consider it a replacement of `<a/>` for in-app\nroutes. Except you supply a `to` attribute instead of a `href`. An example usage:\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\nStruct variants work as expected too:\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew v0.19 out now!\" }</Link<Route>>\n```\n\n#### Navigator API\n\nNavigator API is provided for both function components and struct components. They enable callbacks to change the\nroute. An `Navigator` instance can be obtained in either cases to manipulate the route.\n\n##### Function Components\n\nFor function components, the `use_navigator` hook re-renders the component when the underlying navigator provider changes.\nHere's how to implement a button that navigates to the `Home` route when clicked.\n\n```rust ,ignore\n#[function_component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\nThe example here uses `Callback::from`. Use a normal callback if the target route can be the same with the route\nthe component is in, or just to play safe. For example, when you have a logo button on every page, that goes back to\nhome when clicked, clicking that button twice on home page causes the code to panic because the second click pushes an\nidentical Home route and the `use_navigator` hook won't trigger a re-render.\n:::\n\nIf you want to replace the current location instead of pushing a new location onto the stack, use `navigator.replace()`\ninstead of `navigator.push()`.\n\nYou may notice `navigator` has to move into the callback, so it can't be used again for other callbacks. Luckily `navigator`\nimplements `Clone`, here's for example how to have multiple buttons to different routes:\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[function_component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### Struct Components\n\nFor struct components, the `Navigator` instance can be obtained through the `ctx.link().navigator()` API. The rest is\nidentical with the function component case. Here's an example of a view function that renders a single button.\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### Redirect\n\n`yew-router` also provides a `<Redirect />` component in the prelude. It can be used to achieve similar effects as the\nnavigator API. The component accepts a\n`to` attribute as the target route. When a `<Redirect/>` is rendered users will be redirect to the route specified in props.\nHere is an example:\n\n```rust ,ignore\n#[function_component(SomePage)]\nfn some_page() -> Html {\n    // made-up hook `use_user`\n    let user = match use_user() {\n        Some(user) => user,\n        // Redirects to the login page when user is `None`.\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... actual page content.\n}\n```\n\n:::tip `Redirect` vs `Navigator`, which to use\nThe Navigator API is the only way to manipulate route in callbacks.\nWhile `<Redirect />` can be used as return values in a component. You might also want to use `<Redirect />` in other\nnon-component context, for example in the switch function of a [Nested Router](#nested-router).\n:::\n\n### Listening to Changes\n\n#### Function Components\n\nYou can use `use_location` and `use_route` hooks. Your components will re-render when\nprovided values change.\n\n#### Struct Components\n\nIn order to react on route changes, you can pass a callback closure to the `add_location_listener()` method of `ctx.link()`.\n\n:::note\nThe location listener will get unregistered once it is dropped. Make sure to store the handle inside your\ncomponent state.\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // handle event\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` and `ctx.link().route::<R>()` can also be used to retrieve the location and the route once.\n\n### Query Parameters\n\n#### Specifying query parameters when navigating\n\nIn order to specify query parameters when navigating to a new route, use either `navigator.push_with_query` or\nthe `navigator.replace_with_query` functions. It uses `serde` to serialize the parameters into query string for the URL so\nany type that implements `Serialize` can be passed. In its simplest form this is just a `HashMap` containing string\npairs.\n\n#### Obtaining query parameters for current route\n\n`location.query` is used to obtain the query parameters. It uses `serde` to deserialize the parameters from query string\nin the URL.\n\n## Nested Router\n\nNested router can be useful when the app grows larger. Consider the following router structure:\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nThe nested `SettingsRouter` handles all urls that start with `/settings`. Additionally, it redirects urls that are not\nmatched to the main `NotFound` route. So `/settings/gibberish` will redirect to `/404`.\n\n:::caution\n\nThough note that this is still work in progress so the way we do this is not final\n\n:::\n\nIt can be implemented with the following code:\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[function_component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### Basename\n\nIt's possible to define a basename with `yew-router`.\nA basename is a common prefix of all routes. Both the Navigator API and\n`<Switch />` component respect basename setting. All pushed routes will be\nprefixed with the basename and all switches will strip the basename before\ntrying to parse the path into a `Routable`.\n\nIf a basename prop is not supplied to the Router component, it will use\nthe href attribute of the `<base />` element in your html file and\nfallback to `/` if no `<base />` presents in the html file.\n\n## Relevant examples\n\n- [Router](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/router)\n\n## API Reference\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/concepts/suspense.mdx",
    "content": "---\ntitle: 'Suspense'\ndescription: 'Suspense for data fetching'\n---\n\nSuspense is a way to suspend component rendering whilst waiting a task\nto complete and a fallback (placeholder) UI is shown in the meanwhile.\n\nIt can be used to fetch data from server, wait for tasks to be completed\nby an agent, or perform other background asynchronous task.\n\nBefore suspense, data fetching usually happens after (Fetch-on-render) or before\ncomponent rendering (Fetch-then-render).\n\n### Render-as-You-Fetch\n\nSuspense enables a new approach that allows components to initiate data request\nduring the rendering process. When a component initiates a data request,\nthe rendering process will become suspended and a fallback UI will be\nshown until the request is completed.\n\nThe recommended way to use suspense is with hooks.\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[function_component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[function_component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\nIn the above example, the `use_user` hook will suspend the component\nrendering while user information is loading and a `Loading...` placeholder will\nbe shown until `user` is loaded.\n\nTo define a hook that suspends a component rendering, it needs to return\na `SuspensionResult<T>`. When the component needs to be suspended, the\nhook should return a `Err(Suspension)` and users should unwrap it with\n`?` in which it will be converted into `Html`.\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n# Complete Example\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // implementation omitted.\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // implementation omitted.\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[function_component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[function_component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### Use Suspense in Struct Components\n\nIt's not possible to suspend a struct component directly. However, you\ncan use a function component as a [HOC](../advanced-topics/struct-components/hoc) to\nachieve suspense-based data fetching.\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[function_component(WithUser)]\nfn with_user<T>() -> HtmlResult\nwhere T: BaseComponent\n{\n    let user = use_user()?;\n\n    Ok(html! {<T {user} />})\n}\n\n#[derive(Debug, PartialEq, Properties)]\npub struct UserContentProps {\n    pub user: User,\n}\n\npub struct BaseUserContent;\n\nimpl Component for BaseUserContent {\n    type Properties = UserContentProps;\n    type Message = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let name = ctx.props().user.name;\n\n        html! {<div>{\"Hello, \"}{name}{\"!\"}</div>}\n    }\n}\n\npub type UserContent = WithUser<BaseUserContent>;\n```\n\n## Relevant examples\n\n- [Suspense](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/suspense)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'Build a sample app'\n---\n\nOnce you have the environment ready, you can either choose to use a starter template that contains\nthe boilerplate needed for a basic Yew app or manually set up a small project.\n\n## Using a starter template\n\nInstall [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) by following their installation instructions\nthen run the following commands:\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\nChange directory into your newly created project, then:\n\n```\ntrunk serve\n```\n\n## Setting up the application manually\n\n### Create Project\n\nTo get started, create a new cargo project.\n\n```bash\ncargo new yew-app\n```\n\nOpen the newly created directory.\n\n```bash\ncd yew-app\n```\n\n### Run a hello world example\n\nTo verify the Rust environment is setup, run the initial project using `cargo run`. You should see\na \"Hello World!\" message.\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### Setting up the project as a Yew web application\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\n\n#### Update Cargo.toml\n\nAdd `yew` to the list of dependencies editing file:\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.20.0\", features = [\"csr\"] }\n```\n\nor using `cargo add yew -F csr`.\n\n:::info\n\nYou only need feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n#### Update main.rs\n\nWe need to generate a template which sets up a root Component called `App` which renders a button\nthat updates its value when clicked. Replace the contents of `src/main.rs` with the following code.\n\n:::note\nThe call to `yew::Renderer::<App>::new().render()` inside the `main` function starts your application and mounts\nit to the page's `<body>` tag. If you would like to start your application with any dynamic\nproperties, you can instead use `yew::Renderer::<App>::with_props(..).render()`.\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[function_component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### Create index.html\n\nFinally, add an `index.html` file in the root directory of your app.\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## View your web application\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve\n```\n\n:::info\nAdd option '--open' to open your default browser `trunk serve --open`.\n:::\n\nTrunk will rebuild your application if you modify any of its source code files.\nThis will fail if the socket is being used by another application.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\n## Congratulations\n\nYou have now successfully setup your Yew development environment, and built your first web application.\n\nExperiment with this application and review the [examples](./examples.mdx) to further your learning.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'Editor Setup'\ndescription: 'Setting your code editor'\n---\n\n:::important contribute\nUsing a different editor? Feel free to add instructions for your editor of choice.\n:::\n\n## Add a template for creating components\n\n### JetBrains IDEs\n\n1. Navigate to File | Settings | Editor | Live Templates.\n2. Select Rust and click on the + icon to add a new Live Template.\n3. Give it a name and description of your preference.\n4. Paste the following snippet(s) into the Template Text section.\n5. Change the applicability on the lower right, select Rust > Item > Module\n\nFor function components, use the following template.\n\n- (Optional) Click on Edit Variable and give `tag` a reasonable default value like \"div\", with double quotes.\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[function_component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\nFor struct components, you can use the following more complicated template.\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. Navigate to File > Preferences > User Snippets.\n2. Select Rust as the language.\n3. Add the following snippet in the snippet JSON file:\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[function_component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## Support for the `html!` Macro\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew extension\n\n> 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)\n\nRust-Yew extension is [available on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlight, renames, hover, and more.\n\nEmmet support should work out of the box, if not please fall back to editing the `settings.json` file:\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/getting-started/examples.mdx",
    "content": "---\ntitle: 'Examples'\n---\n\nThe Yew repository contains many [examples] (in various states of maintenance).\nWe recommend perusing them to get a feel for how to use different features of the framework.\nWe also welcome Pull Requests and issues for when they inevitably get neglected and need some ♥️\n\nFor more details including a list of examples, refer to the [README].\n\n:::tip\nMost of the examples have a live deployment that can be found at `https://examples.yew.rs/< example_name >`.\nClick the shield on their individual README page in their respective sub-folder to navigate to the live demo.\n:::\n\n[examples]: https://github.com/yewstack/yew/tree/yew-v0.20.0/examples\n[readme]: https://github.com/yewstack/yew/tree/yew-v0.20.0/examples#yew-examples\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/getting-started/introduction.mdx",
    "content": "---\ntitle: 'Getting Started'\n---\n\nYou will need a couple of tools to compile, build, package and debug your Yew application.\nWhen getting started, we recommend using [Trunk](https://trunkrs.dev/). Trunk is a WASM web application\nbundler for Rust.\n\n## Installing Rust\n\nTo install Rust, follow the [official instructions](https://www.rust-lang.org/tools/install).\n\n:::important\nThe minimum supported Rust version (MSRV) for Yew is `1.56.1`. Older versions can cause unexpected\nissues accompanied by incomprehensible error messages. You can check your toolchain version using\n`rustup show` (under \"active toolchain\") or alternatively `rustc --version`. To update your\ntoolchain, run `rustup update`.\n:::\n\n## Install WebAssembly target\n\nRust can compile source codes for different \"targets\" (e.g. different processors). The compilation\ntarget for browser-based WebAssembly is called `wasm32-unknown-unknown`. The following command will\nadd the WebAssembly target to your development environment.\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Install Trunk\n\nTrunk is the recommended tool for managing deployment and packaging, and is used throughout the\ndocumentation and examples.\n\n```shell\n# note that this might take a while to install, because it compiles everything from scratch\n# Trunk also provides prebuilt binaries for a number of major package managers\n# See https://trunkrs.dev/#install for further details\ncargo install --locked trunk\n```\n\n### Other options\n\nThere are options other than Trunk that may be used for bundling Yew applications. You might want to try one of these options:\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (still in early development)\n\n## Next steps\n\nWith your development environment setup, you can now proceed with reading the documentation.\nIf you like to learn by getting your hands dirty, we recommend you check out our [tutorial](../tutorial)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/migration-guides/yew/from-0_18_0-to-0_19_0.mdx",
    "content": "---\ntitle: 'From 0.18.0 to 0.19.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`Yew 0.19.0` has changed a lot, thus this migration will not cover ALL of the changes.\n\nInstead only the most impactful changes are mentioned and the rest should be picked up by `cargo`.\n\n## `html!` requirement for braces around most props\n\nThe syntax of the `html!` macro has been updated, such that in most cases you will need to enclose\nprops with braces.\n\n<Tabs>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust {4}, ignore\nlet super_age = 1;\nhtml!{\n    <JapaneseYew\n        age=super_age // ! Will throw an error\n    >\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Valid\" label=\"Valid\">\n\n```rust {4}, ignore\nlet super_age = 1;\nhtml!{\n    <JapaneseYew\n        age={super_age} // Correct\n    >\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Shorthand\" label=\"Shorthand\">\n\nShorthand initialization has been added:\n\n```rust {4}, ignore\nlet age = 1;\nhtml!{\n    <JapaneseYew\n        {age}\n    >\n}\n```\n\n  </TabItem>\n</Tabs>\n\nThere is a community provided regex to help automate the update, though we can't promise it will work\nall the time.\n\nIt breaks when it encounters closures (specifically the `|_|` syntax).\n\nfind with `=(?![{\">=\\s])([^\\s></]*(\\s!{0,1}[=|&]{2}\\s[^\\s></]*)*)`\n\nreplace with `={$1}`\n\n## Function components\n\n[Function components](concepts/function-components/introduction.mdx) are a brand new way to write components that\nrequires less boilerplate than their structural counterpart.\n\nWhile this change does not force you to change your codebase, as you migrate from `0.18` to `0.19`, this migration time might present a good opportunity to start using them in your codebase.\n\n## Struct components lifecycle methods and ctx\n\n[Struct components](advanced-topics/struct-components/introduction.mdx) also received changes to their API.\n\n### ShouldRender removed in favor of bool\n\n`ShouldRender` removed in favor of `bool` and can be just find all - replaced throughout your code base.\n\n### ctx, props, link\n\nStruct components no longer own props and link, instead they receive `ctx: &Context<Self>` argument in lifetime methods that can later give you access to `ctx.props() -> &Properties` and `ctx.link() -> &Scope<Self>`.\n\nYou will need to remove `link` and `props` from your component struct fields as such all lifetime methods got updated.\n\n### Lifetime methods in Component trait\n\nFor new API look in the [Component trait](https://github.com/yewstack/yew/blob/9b6bc96826d53ec38aa3ecc02e3a1e132692c411/packages/yew/src/html/component/mod.rs#L37-L97)\n\n## `web-sys` is no longer re-exported\n\nAdd `web-sys` as your project dependency and one by one add the needed features like `Event` or `Window`.\n\n## Services\n\nDuring this update all services were removed in favor of community driven solutions like [gloo](https://github.com/rustwasm/gloo)\n\nRemove this entirely. `yew-services` adds a layer a abstraction which makes it easier to call external resources. This is all well and good but this layer is supposed to be specific to Yew. It would be better if an framework agnostic abstraction existed instead.\n\n- `ConsoleService`\n  Use [gloo-console](https://crates.io/crates/gloo-console) or [`weblog`](https://crates.io/crates/weblog) instead.\n- `DialogService`\n  Use [`gloo-dialogs`](https://docs.rs/gloo-dialogs/) instead.\n- `IntervalService`\n  Use [`gloo-timers`](https://docs.rs/gloo-timers/) instead.\n- `KeyboardService`\n  `on*` event handlers in yew already handle it. Using this service is even more cumbersome because it requires use of `NodeRef` in order to call any functions provided by it.\n\n```rust ,ignore\nlet onkeydown = Callback::from(|e| {\n    e.prevent_default();\n    todo!(\"use `e`, just like in service methods.\");\n});\nhtml! {\n    <input {onkeydown} />\n}\n```\n\n- `ResizeService`\n  Use [`gloo-events`](https://docs.rs/gloo-events) to attach the listener instead.\n- `StorageService`\n  Use [`gloo-storage`](https://docs.rs/gloo-storage/) instead.\n- `TimeoutService`\n  Use [`gloo-timers`](https://docs.rs/gloo-timers/) instead.\n- `WebSocketService`\n  Use [`wasm-sockets`](https://github.com/scratchyone/wasm-sockets) or [`gloo-net`](https://crates.io/crates/gloo-net) instead.\n- `FetchService`\n  Use [`reqwest`](https://crates.io/crates/reqwest) or [`gloo-net`](https://crates.io/crates/gloo-net) instead.\n\n## New crate - yew-agent\n\nYew agents were removed to a separate crate, see [yew agents migration guide](./../yew-agent/from-0_0_0-to-0_1_0)\n\n## Ending note\n\nWe are sorry if some things are not covered in this guide as it was truly a huge update and we hope\nthat the uncovered issues will be clearly explained in error messages emitted by the Rust compiler.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/migration-guides/yew/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\n## `_as_body` variant of `start_app` is removed\n\nThis method of controlling body has caused issues in event registration and\nSSR hydration. They have been removed. Read more in the [github issue](https://github.com/yewstack/yew/pull/2346).\n\n## New Hooks and Function Components API\n\nThe Function Components and Hooks API are re-implemented with a different mechanism:\n\n- User-defined hooks are now required to have a prefix `use_` and must be marked with the `#[hook]` attribute.\n- Hooks will now report compile errors if they are not called from the top level of a function component\n  or a user defined hook. The limitation existed in the previous version of Yew as well. In this version,\n  It is reported as a compile time error.\n\n## Automatic Message Batching\n\nThe scheduler now schedules its start to the end of the browser event loop.\nAll messages queued during in the meantime will be run in batch.\nThe running order of messages between components are no longer guaranteed, but\nmessages sent to the same component is still acknowledged in an FIFO order.\nIf multiple updates will result in a render, the component will be rendered\nonce.\n\n:::info What this means to developers?\n\nFor struct components, this means that if you send 2 messages to 2 different\ncomponents, they will not be guaranteed to be seen in the same order they are\nsent. If you send 2 messages to the same component, they will still be passed\nto the component in the order they are sent. The messages are not sent to the\ncomponent immediately so you should not assume that when the component receives\na message it still has the same state at the time the message is created.\n\nFor function components, if you store states with `use_state(_eq)`\nand the new value of that state depends on the previous value,\nyou may want to switch to `use_reducer(_eq)`. The new value of the state will\nnot be visible / acknowledged until the next time the component is rendered.\nThe reducer action works similar to messages for struct components and\nwill be sent to the reducer function in the same order as they are dispatched.\nThe reducer function can see all previous changes at the time they are run.\n\n:::\n\n## Yew Renderer\n\n`start_app*` has been replaced by `yew::Renderer`.\n\nYou need to enable feature `csr` to use `yew::Renderer`.\n\nFor example, to use client side rendering to render a typical app component:\n\n```rust ,ignore\nyew::Renderer::<App>::new().render();\n```\n\nFor more options, see [the docs](https://docs.rs/yew/0.20/yew/struct.Renderer.html).\n\n## `ref` prop for Components\n\nComponents no longer have a `ref` prop. Trying to add a node ref to a component\nwill result in a compile error\n\nPreviously node ref passed to a component was bound to the first element rendered by it.\nIf this behavior is still desired, it is recommended to use add a `r#ref` field to the\ncomponent's properties and bind it manually\n\n## `changed` Method on Components\n\nThe method `fn changed()` has now a new argument to provide the old properties\nto the function.\n\nThe old method's signature was:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>) -> bool\n```\n\nThe new method's signature is now:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool\n```\n\nThis can be adjusted automatically in your code using this bash script (save\nyour code before running this!):\n\n```bash\nperl -p -i -e  's/fn changed\\(&mut self, (\\w+): &Context<Self>\\)/fn changed(&mut self, $1: &Context<Self>, _old_props: &Self::Properties)/g' $(find . -name \\*.rs)\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/migration-guides/yew-agent/from-0_0_0-to-0_1_0.mdx",
    "content": "---\ntitle: 'From 0.0.0 to 0.1.0'\n---\n\nThis is the first release of `yew-agents` being separated from `yew`\n\nThe only thing you will need to do is change the import paths from `yew::*` to `yew_agents::*`\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/migration-guides/yew-agent/from-0_1_0-to-0_2_0.mdx",
    "content": "---\ntitle: 'From 0.1.0 to 0.2.0'\n---\n\n## Removal of `Context` and `Job` Agents\n\nThe `Context` and `Job` Agents have been removed in favour of Yew's Context API.\n\nYou can see the updated [`contexts`](https://github.com/yewstack/yew/tree/yew-v0.20.0/examples/contexts)\nwhich demonstrate how to use the context API.\n\nFor users of `yew_agent::utils::store`, you may switch to third party solutions like: [Yewdux](https://github.com/intendednull/yewdux) or [Bounce](https://github.com/futursolo/bounce).\n\n## `Threaded` has been separated into `PublicAgent` and `PrivateAgent`\n\nReplace `use yew_agent::Threaded;` with `use yew_agent::PublicAgent;`.\n\n:::note\n\n`Threaded` was never implemented for Private Agents.\nAll existing web worker-based agents are Public Agents.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/migration-guides/yew-router/from-0_15_0-to-0_16_0.mdx",
    "content": "---\ntitle: 'From 0.15.0 to 0.16.0'\n---\n\nThe router API has been completely rewritten in `0.16.0`.\n\nBecause it is such a radical change, there are too many things to list out here, so we highly\nrecommend to read the updated [router documentation](./../../concepts/router) and adapt your app\naccordingly.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/migration-guides/yew-router/from-0_16_0-to-0_17_0.mdx",
    "content": "---\ntitle: 'From 0.16.0 to 0.17.0'\n---\n\n## `Switch::render` is no longer needed\n\nThe `<Switch />` component now accepts a closure of `Fn(Routable) -> Html` as\nthe render function directly.\n\n## `navigator` API\n\nThe History API has been replaced with the Navigator API.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nA proposal for integrated CSS support can be found here:\n[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\nThis contains a lot of discussion about how to best integrate CSS support into Yew.\n\nCurrently, the approach we've adopted is to encourage developers to build a number of systems, before\nadopting the most popular one.\n\nThe community are currently developing a number of projects to make it easy to add styles to\nprojects. A few are given below:\n\n#### Component Libraries\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - A styling framework for Yew without any JavaScript dependencies.\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design Components.\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS Components.\n- [Yewtify](https://github.com/yewstack/yewtify) – Implements the features provided by the Vuetify framework in Yew.\n\n#### Styling Solutions\n\n- [stylist](https://github.com/futursolo/stylist-rs) - A CSS-in-Rust styling solution for WebAssembly Applications.\n\n:::important contribute\nIf you're developing a project adding styles to Yew please submit a PR adding yourself to this list!\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/more/debugging.mdx",
    "content": "---\ntitle: 'Debugging'\n---\n\n## Panics\n\nYew automatically logs panics in the browser console.\n\n## Console Logging\n\nIn JavaScript, `console.log()` is used to log to the browser console. Some options for Yew are listed below.\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate integrates with [`log`](https://crates.io/crates/log) crate to send the log level, source line and filename to the browser console.\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nThis crate is part of Gloo, a collection of libraries providing ergonomic Rust wrappers for browser APIs.\nThe `log!` macro can take a `JsValue` directly which is slightly easier to use than `wasm_logger`.\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` can be used with [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) to output messages to the browser console.\n\n```rust, ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## Debugging component lifecycles\n\n[`tracing`](https://crates.io/crates/tracing) can be used to collect event information related to a component's lifecycle. `tracing` also comes with a feature flag for `log` support, which integrates nicely with `wasm-logger`.\n\n[Compile time filters](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) can be used to adjust verbosity or disable logging, which should result in a smaller Wasm file.\n\n## Source Maps\n\nThere is [some support](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) for source maps.\nHowever, some configuration is required.\n\n## Past Articles\n\nSome past articles on the state of debugging in WebAssembly in Rust can be found below. They may serve as interesting reads.\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) don’t support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/more/deployment.mdx",
    "content": "---\ntitle: 'Deployment'\ndescription: 'Deploying Yew applications'\n---\n\nWhen you are ready to deploy your Yew application to a server, you have various options for deployment.\n\n`trunk build --release` builds your app in release mode. Set up your HTTP server so that it serves `index.html` whenever your site is visited, and requests to static paths like `index_<hash>.js` and `index_bg_<hash>.wasm` are served with the contents of their respective contents from the dist directory generated by trunk.\n\n:::important A note about `trunk serve --release`\nDo **not** use `trunk serve --release` to serve your application in production.\nIt should only be used for testing the release build during development\n:::\n\n## Server configuration\n\n### Serving `index.html` as fallback\n\nIf the application uses the [Yew router](concepts/router.mdx), you must configure the server to return the `index.html` when asked for a file that it does not have.\n\nAn application with Yew router is built as a [Single Page Application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA). When the user navigates to a URL from within a running client, the router interprets the URL and routes to that page.\n\nBut on a fresh load, such as when navigating to the page by entering it in the address bar or refreshing the page, all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router. A wrongly configured server would return with status 404 - Not Found.\n\nBy returning `index.html` instead, the app loads as it normally would as if request was for `/`, until the router notices that the route is `/show/42` and displays the appropriate contents.\n\n### Configuring correct MIME-type for Web Assembly asset.\n\nThe WASM files must be served with the [Content-Type header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) set to `application/wasm` MIME-type.\n\nMost servers and hosting services already do this by default. If yours doesn't, consult its documentation. An incorrect MIME-type will, in most web browsers, result in an error similar to the following:\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## Building for Relative Paths\n\nBy default, trunk will assume that your site is being served at `/` and build the site accordingly. This behavior can be overridden by adding `<base data-trunk-public-url />` to the `index.html` file. Trunk rewrites this tag to contain the value passed to `--public-url`. Yew router automatically detects the presence of `<base />` and handles it appropriately.\n\n## Customizing behavior using environment variables\n\nIt's common to customize the build environment by using environment variables. Since the app is run in browser, we can't read the environment variables at runtime.\nThe [`std::env!`](https://doc.rust-lang.org/std/macro.env.html) macro can be used to obtain a value of an environment variables at compile time.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/more/roadmap.mdx",
    "content": "---\ntitle: 'Roadmap'\ndescription: 'The planned feature roadmap for the Yew framework'\n---\n\n## Prioritization\n\nThe prioritization of upcoming features and focuses of the framework is determined by the community.\nIn Spring 2020, a developer survey was sent out to collect feedback on the direction of the project.\nYou can find the summary in the [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D).\n\n:::note\nStatus of all major initiatives can be tracked on the Yew Github [project board](https://github.com/yewstack/yew/projects)\n:::\n\n## Focuses\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Most requested features\n\n1. [Functional Components](https://github.com/yewstack/yew/projects/3)\n2. [Component Library](https://github.com/yewstack/yew/projects/4)\n3. Better state management\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n### Issues needed for production readiness\n\n- Improve Yew test coverage\n- Reduce binary size\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- Create tutorial\n- Simplify project setup\n\n### Pain points\n\n- [Component boilerplate](https://github.com/yewstack/yew/issues/830)\n- [Agents](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/more/testing.mdx",
    "content": "---\ntitle: 'Testing apps'\ndescription: 'Testing your app'\n---\n\n:::info\nWe're working on making it easy to test components, but this is currently a work in progress.\n\nSupport for [shallow rendering](https://github.com/yewstack/yew/issues/1413) can be found in the GitHub repository.\n:::\n\n## Snapshot testing\n\nYew exposes the `yew::tests::layout_tests` module to facilitate with snapshot testing of components.\n\n:::important contribute\nHelp improve the documentation for snapshot testing.\n:::\n\n## wasm_bindgen_test\n\nThe Rust/WASM working group maintains a crate called [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nwhich allows you to run tests in a browser in similar fashion to how the built-in `#[test]` procedural macro works.\nMore information is given in the [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nfor this module.\n"
  },
  {
    "path": "website/versioned_docs/version-0.20/tutorial/index.mdx",
    "content": "---\ntitle: 'Tutorial'\nslug: /tutorial\n---\n\n## Introduction\n\nIn this hands-on tutorial, we will take a look at how we can use Yew to build web applications.\n**Yew** is a modern [Rust](https://www.rust-lang.org/) framework for building front-end web apps using [WebAssembly](https://webassembly.org/).\nYew encourages a reusable, maintainable, and well-structured architecture by leveraging Rust's powerful type system.\nA large ecosystem of community-created libraries, known in Rust as [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html),\nprovide components for commonly-used patterns such as state management.\n[Cargo](https://doc.rust-lang.org/cargo/), the package manager for Rust, allows us to take advantage of the\nnumerous crates available on [crates.io](https://crates.io), such as Yew.\n\n### What we are going to build\n\nRustconf is an intergalactic gathering of the Rust community that happens annually.\nRustconf 2020 had a plethora of talks that provided a good amount of information.\nIn this hands-on tutorial, we will be building a web application to help fellow Rustaceans\nget an overview of the talks and watch them all from one page.\n\n## Setting up\n\n### Prerequisites\n\nThis tutorial assumes you're already familiar with Rust. If you're new to Rust,\nthe free [Rust Book](https://doc.rust-lang.org/book/ch00-00-introduction.html) offers a great starting point for\nbeginners and continues to be an excellent resource even for experienced Rust developers.\n\nEnsure the latest version of Rust is installed by running `rustup update` or by\n[installing rust](https://www.rust-lang.org/tools/install) if you haven't already done so.\n\nAfter installing Rust, you can use Cargo to install `trunk` by running:\n\n```bash\ncargo install trunk\n```\n\nWe will also need to add the WASM build target by running:\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### Setting up the project\n\nFirst, create a new cargo project:\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nTo verify the Rust environment is set up properly, run the initial project using the cargo build tool.\nAfter output about the build process, you should see the expected \"Hello, world!\" message.\n\n```bash\ncargo run\n```\n\n## Our first static page\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\nUpdate the files as follows:\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.20\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[function_component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nNow, let's create an `index.html` at the root of the project.\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### Start the development server\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve --open\n```\n\nTrunk will open your application in your default browser, watch the project directory and helpfully rebuild your\napplication if you modify any source files. Remove option '--open' to not open your default browser.\nThis will fail if the socket is being used by another application.\nBy default server will be listening at address '127.0.0.1' and port '8080' [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8080\n```\n\nIf you are curious, you can run `trunk help` and `trunk help <subcommand>` for more details on what's happening.\n\n### Congratulations\n\nYou have now successfully set up your Yew development environment and built your first Yew web application.\n\n## Building HTML\n\nYew makes use of Rust's procedural macros and provides us with a syntax similar to JSX (an extension to JavaScript\nwhich allows you to write HTML-like code inside of JavaScript) to create the markup.\n\n### Converting classic HTML\n\nSince we already have a pretty good idea of what our website will look like, we can simply translate our mental draft\ninto a representation compatible with `html!`. If you're comfortable writing simple HTML, you should have no problem\nwriting marking inside `html!`. It is important to note that the macro does differ from HTML in a few ways:\n\n1. Expressions must be wrapped in curly braces (`{ }`)\n2. There must only be one root node. If you want to have multiple elements without wrapping them in a container,\n   an empty tag/fragment (`<> ... </>`) is used\n3. Elements must be closed properly.\n\nWe want to build a layout that looks something like this in raw HTML:\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nNow, let's convert this HTML into `html!`. Type (or copy/paste) the following snippet into the body of `app` function\nsuch that the value of `html!` is returned by the function\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\nRefresh the browser page, and you should see the following output displayed:\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### Using Rust language constructs in the markup\n\nA big advantage of writing markup in Rust is that we get all the coolness of Rust in our markup.\nNow, instead of hardcoding the list of videos in the html, let's actually define them as a `Vec` of Rust objects.\nWe'll create a simple `struct` (in `main.rs` or any file of our choice) which will hold our data.\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\nNext, we will create instances of this struct in our `app` function and use those instead of hardcoding the data:\n\n```rust\nuse website_test::tutorial::Video; // replace with your own path\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\nIn order to display them, we need to convert these `Vec`s into `Html`. We can do that by creating an iterator,\nmapping it to `html!` and collecting it as `Html`:\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\nKeys on list items helps Yew keep track of which items have changed in the list, resulting in faster re-renders. [It is always recommended to use keys in lists](/concepts/html/lists.mdx#keyed-lists).\n:::\n\nAnd finally we need to replace the hardcoded list of videos with the `Html` we created from data:\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## Components\n\nComponents are the building blocks of Yew applications. By combining components, which can be made of other components,\nwe build our application. By structuring our components for re-usability and keeping them generic, we will be able to use\nthem in multiple parts of our application without having to duplicate code or logic.\n\nIn fact, the `app` function we have been using so far is a component, called `App`. It is a \"function component\".\nThere are two different types of components in Yew.\n\n1. Struct Components\n2. Function Components\n\nIn this tutorial, we will be using function components.\n\nNow, let's split up our `App` component into smaller components. We'll begin by extracting the videos list into\nits own component.\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[function_component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\nNotice the parameters of our `VideosList` function component. A function component takes only one argument which\ndefines its \"props\" (short for \"properties\"). Props are used to pass data down from a parent component to a child component.\nIn this case, `VideosListProps` is a struct which defines the props.\n\n:::important\nThe struct used for props must implement `Properties` by deriving it.\n:::\n\nIn order for the above code to compile, we need to modify the `Video` struct like:\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\nNow, we can update our `App` component to make use of `VideosList` component.\n\n```rust ,ignore {4-7,13-14}\n#[function_component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nBy looking at the browser window, we can verify that the lists are rendered as they should be.\nWe have moved the rendering logic of lists to its own component. This shortens the `App` component’s source code,\nmaking it easier for us to read and understand.\n\n### Making it interactive\n\nThe final goal here is to display the selected video. In order to do that, `VideosList` component needs to \"notify\" its\nparent when a video is selected, which is done via a `Callback`. This concept is called \"passing handlers\".\nWe modify its props to take an `on_click` callback:\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\nThen we modify the `VideosList` component to pass the \"emit\" the selected video to the callback.\n\n```rust ,ignore {2-4,6-12,15-16}\n#[function_component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\nNext, we need to modify the usage of `VideosList` to pass that callback. But before doing that, we should create\na new component, `VideoDetails`, component that is displayed when a video is clicked.\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[function_component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\nNow, modify the `App` component to display `VideoDetails` component whenever a video is selected.\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[function_component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\nDon't worry about the `use_state` right now, we will come back to that later.\nNote the trick we pulled with `{ for details }`. `Option<_>` implements `Iterator` so we can use it to display the only\nelement returned by the `Iterator` with a special `{ for ... }` syntax\n[supported by the `html!` macro](concepts/html/lists).\n\n### Handling state\n\nRemember the `use_state` used earlier? That is a special function, called a \"hook\". Hooks are used to \"hook\" into\nthe lifecycle of a function component and perform actions. You can learn more about this hook, and others\n[here](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks).\n\n:::note\nStruct components act differently. See [the documentation](advanced-topics/struct-components/introduction.mdx) to learn about those.\n:::\n\n## Fetching data (using external REST API)\n\nIn a real world application, data will usually come from an API instead of being hardcoded. Let's fetch our\nvideos list from external source. For this we will need to add the following crates:\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  For making the fetch call.\n- [`serde`](https://serde.rs) with derive features\n  For de-serializing the JSON response\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  For executing Rust Future as a Promise\n\nLet's update the dependencies in `Cargo.toml` file:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.2\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\nUpdate the `Video` struct to derive the `Deserialize` trait:\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\nNow as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[function_component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with_deps(move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        }, ());\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\nWe're using `unwrap`s here because this is a demo application. In a real world app, you would likely want to have\n[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).\n:::\n\nNow look at the browser to see everything working as expected... which would've been the case if it weren't for CORS.\nIn order to fix that, we need a proxy server. Luckily trunk provides that.\n\nUpdate the following line:\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\nNow, rerun the server with the following command:\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nRefresh the tab and everything should work as expected.\n\n## Wrapping up\n\nCongratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.\n\n## What's next\n\nObviously, this application is very far from perfect or useful. After going through this tutorial,\nyou can use it as a jumping-off point to explore more advanced topics.\n\n### Styles\n\nOur apps look very ugly. There's no CSS, or any kind of styles.\nUnfortunately, Yew doesn't offer a built-in way to style components. See [Trunk's assets](https://trunkrs.dev/assets/)\nto learn how to add style sheets.\n\n### More libraries\n\nOur app made use of only a few external dependencies. There are lots of crates out there that can be used.\nSee [external libraries](/community/external-libs) for more details.\n\n### Learning more about Yew\n\nRead our [official documentation](../getting-started/introduction.mdx). It explains a lot of concepts in much more details.\nTo learn more about our the Yew API, see our [API docs](https://docs.rs/yew).\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[function_component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[function_component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! { for modified_children }\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: 'Low level details about the framework'\n---\n\n# Low-level library internals\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: 'Optimizations & Best Practices'\nsidebar_label: Optimizations\ndescription: 'Make your app faster'\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nTo avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications, it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component or just a big\nfunction that produces `Html`. Code that is shared between the crates containing different parts of\nthe application could be stored in a separate crate which the project depends on.\nIn the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and additionally render the component you are working on.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther, it is possible to optimize the size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading:\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[function_component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/server-side-rendering.md",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[function_component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[function_component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'Lifecycle'\ndescription: 'Components and their lifecycle hooks'\n---\n\nThe `Component` trait has a number of methods which need to be implemented; Yew will call these at different\nstages in the lifecycle of a component.\n\n## Lifecycle\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## Lifecycle Methods\n\n### Create\n\nWhen a component is created, it receives properties from its parent component and is stored within\nthe `Context<Self>` that is passed down to the `create` method. The properties can be used to\ninitialize the component's state and the \"link\" can be used to register callbacks or send messages to the component.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nThe `view` method allows you to describe how a component should be rendered to the DOM. Writing\nHTML-like code using Rust functions can become quite messy, so Yew provides a macro called `html!`\nfor declaring HTML and SVG nodes (as well as attaching attributes and event listeners to them) and a\nconvenient way to render child components. The macro is somewhat similar to React's JSX (the\ndifferences in programming language aside).\nOne difference is that Yew provides a shorthand syntax for properties, similar to Svelte, where instead of writing `onclick={onclick}`, you can just write `{onclick}`.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\nFor usage details, check out [the `html!` guide](concepts/html/introduction.mdx).\n\n### Rendered\n\nThe `rendered` component lifecycle method is called once `view` has been called and Yew has rendered\nthe results to the DOM, but before the browser refreshes the page. This method is useful when you\nwant to perform actions that can only be completed after the component has rendered elements. There\nis also a parameter called `first_render` which can be used to determine whether this function is\nbeing called on the first render, or instead a subsequent one.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nNote that this lifecycle method does not require implementation and will do nothing by default.\n:::\n\n### Update\n\nCommunication with components happens primarily through messages which are handled by the\n`update` lifecycle method. This allows the component to update itself\nbased on what the message was, and determine if it needs to re-render itself. Messages can be sent\nby event listeners, child components, Agents, Services, or Futures.\n\nHere is an example of what an implementation of `update` could look like:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nComponents may be re-rendered by their parents. When this happens, they could receive new properties\nand need to re-render. This design facilitates parent-to-child component communication by just\nchanging the values of a property. There is a default implementation that re-renders the component\nwhen props are changed.\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods but are only caused when trying to update\nthe same component after every render, when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it is often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample, you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to the component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nProperties enable child and parent components to communicate with each other.\nEvery component has an associated properties type which describes what is passed down from the parent.\nIn theory, this can be any type that implements the `Properties` trait, but in practice, there is no\nreason for it to be anything but a struct where each field represents a property.\n\n## Derive macro\n\nInstead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to\nautomatically generate the implementation instead.\nTypes for which you derive `Properties` must also implement `PartialEq`.\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they are set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: 'Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` keyword can be used inside of any HTML element or component to get the DOM `Element` that\nthe item is attached to. This can be used to make changes to the DOM outside of the `view` lifecycle\nmethod.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\nThe syntax is:\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/agents.mdx",
    "content": "---\ntitle: 'Agents'\ndescription: \"Yew's Actor System\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nAgents are a way to offload tasks to web workers.\n\nIn order for agents to run concurrently, Yew uses\n[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).\n\n## Lifecycle\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## Types of Agents\n\n### Reaches\n\n- Public - There will exist at most one instance of a Public Agent at any given time. Bridges will\n  spawn or connect to an already spawned agent in a web worker.\n  When no bridges are connected to this agent, the agent will disappear.\n\n- Private - Spawn a new agent in a web worker for every new bridge. This is good for moving shared but\n  independent behavior that communicates with the browser out of components. When\n  the connected bridge is dropped, the agent will disappear.\n\n- Global \\(WIP\\)\n\n## Communication between Agents and Components\n\n### Bridges\n\nA bridge allows bi-directional communication between an agent and a component. Bridges also allow agents to communicate with one another.\n\nA `use_bridge` hook is also provided to create bridges in a function component.\n\n### Dispatchers\n\nA dispatcher allows uni-directional communication between a component and an agent. A dispatcher allows a component to send messages to an agent.\n\n## Overhead\n\nAgents use web workers \\(i.e. Private and Public\\). They incur a serialization overhead on the\nmessages they send and receive. Agents use [bincode](https://github.com/servo/bincode) to communicate\nwith other threads, so the cost is substantially higher than just calling a function.\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) example shows how\n  components can send messages to and receive messages from agents.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'CSS with classes!'\ndescription: 'A handy macro to handle classes'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew does not natively provide a CSS-in-Rust solution but helps with styling by providing\nprogrammatic ways to interact with the HTML `class` attribute.\n\n## Classes\n\nThe `classes!` macro and associated `Classes` struct simplify the use of HTML classes:\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\nWe will expand upon this concept in [more CSS](../../more/css).\n\n## Inline Styles\n\nCurrently Yew does not provide any special help with inline styles specified via the `styles` attribute,\nbut you can use it like any other HTML attribute:\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\nWe will expand upon this concept in [more CSS](../../more/css).\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'HTML with html!'\ndescription: 'Its HTML but not quite!'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYou can write expressions resembling HTML with the `html!` macro. Behind the scenes, Yew turns\nit into rust code representing the DOM to generate.\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nSimilar to format expressions, there is an easy way to embed values from the surrounding\ncontext into the HTML by applying curly brackets:\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\nOne major rule comes with the use of `html!` - you can only return 1 wrapping node.\nTo render a list of multiple elements, `html!` allows fragments. Fragments are tags\nwithout a name, that produce no HTML element by themselves.\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// error: only one root HTML element allowed\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// fixed: using HTML fragments\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\nWe will introduce Yew and HTML further in depth in [more HTML](concepts/html/introduction.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JS with RS'\ndescription: 'JavaScript with Rust'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files, while also keeping the underlying technology\n> accessible where necessary.\n\nAs of today, WebAssembly is not feature-complete for DOM interactions. This means even in Yew we\nsometimes rely on calling JavaScript. What follows is an overview of the involved libraries.\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool that bridges calls between JavaScript and Rust functions.\n\nWe highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./wasm-bindgen.mdx).\n\n## web-sys\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs and allows us to write JavaScript code in a rustyfied and safe way.\n\nExample:\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\nOnce again we highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./web-sys.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool to facilitate\nhigh-level interactions between Wasm modules and JavaScript; it is built with Rust by\n[The Rust and WebAssembly Working Group](https://rustwasm.github.io/).\n\nYew uses `wasm-bindgen` to interact with the browser through a number of crates:\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nThis section will explore some of these crates at a high level, to make it easier to understand\nand use `wasm-bindgen` APIs with Yew. For a more in-depth guide to `wasm-bindgen` and its associated\ncrates then check out [The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/).\n\nFor documentation on the above crates check out [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html).\n\n:::tip\nUse the `wasm-bindgen` doc.rs search to find browser APIs and JavaScript types that have been imported\nover using `wasm-bindgen`.\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nThis crate provides many of the building blocks for the rest of the crates above. In this section we\nare only going to cover two main areas of the `wasm-bindgen` crate and that is the macro and some\ntypes/traits you will see pop up again and again.\n\n### `#[wasm_bindgen]` macro\n\nThe `#[wasm_bindgen]` macro provides an interface between Rust and JavaScript, providing a system\nfor translating between the two. Using this macro is more advanced, and you should not need to reach\nfor it unless you are trying to use an external JavaScript library. The `js-sys` and `web-sys`\ncrates expose `wasm-bindgen` definitions for built-in JavaScript types and browser APIs.\n\nLet's go over a simple example of using the `#[wasm-bindgen]` macro to import some specific flavours\nof the [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) function.\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// First up let's take a look of binding `console.log` manually, without the\n// help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations\n// manually ourselves, and the correctness of our program relies on the\n// correctness of these annotations!\n#[wasm_bindgen]\nextern \"C\" {\n\n    // Use `js_namespace` here to bind `console.log(..)` instead of just\n    // `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // The `console.log` is quite polymorphic, so we can bind it with multiple\n    // signatures. Note that we need to use `js_name` to ensure we always call\n    // `log` in JS.\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // Multiple arguments too!\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// using the imported functions!\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_This example was adapted from [1.2 Using console.log of The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html)_.\n\n### Simulating inheritance\n\nInheritance between JavaScript classes is a core feature of the Javascript language and the DOM\n(Document Object Model) is designed around it. When types are imported using `wasm-bindgen` you can\nalso add attributes that describe their inheritance.\n\nIn Rust, this inheritance is represented using the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\nand [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) traits. An example of this\nmight help; so say you have three types `A`, `B`, and `C` where `C` extends `B` which in turn\nextends `A`.\n\nWhen importing these types the `#[wasm-bindgen]` macro will implement the `Deref` and `AsRef`\ntraits in the following way:\n\n- `C` can `Deref` to `B`\n- `B` can `Deref` to `A`\n- `C` can be `AsRef` to `B`\n- Both `C` & `B` can be `AsRef` to `A`\n\nThese implementations allow you to call a method from `A` on an instance of `C` and to use `C` as if\nit was `&B` or `&A`.\n\nIt is important to note that every single type imported using `#[wasm-bindgen]` has the same root type,\nyou can think of it as the `A` in the example above, this type is [`JsValue`](#jsvalue) which has\nits section below.\n\n_[extends section in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) {#jsvalue}\n\nThis is a representation of an object owned by JavaScript, this is a root catch-all type for `wasm-bindgen`.\nBecause JavaScript does not have a strong type system, any type that comes from `wasm-bindgen` is a `JsValue`.\nFunctions in JavaScript do not define the type of any variables they take in or return; variables can be\nany valid JavaScript value, hence `JsValue`. If you are working with imported functions or types that\naccept a `JsValue`, then any imported value is _technically_ valid.\n\nEven though `JsValue` may be accepted by a JS function, that function may still only _actually_ accept certain types.\nPassing an incorrect `JsValue` can lead to an exception which triggers a panic - so when using raw `wasm-bindgen` APIs,\ncheck the your JavaScript's documentation for types of inputs that will cause an exception (and a panic).\n\n_[`JsValue` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)._\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) {#JsCast}\n\nRust has a strong type system and JavaScript...doesn't 😞. For Rust to maintain these\nstrong types but still be convenient, the WebAssembly group came up with a pretty neat trait `JsCast`.\nIts job is to help you move from one JavaScript \"type\" to another, which sounds vague, but it means\nthat if you have one type which you know is another, then you can use the functions of `JsCast`\nto jump from one type to the other. It is a nice trait to get to know when working with `web-sys`,\n`wasm_bindgen`, `js-sys` - you will notice lots of types will implement `JsCast` from those crates.\n\n`JsCast` provides both checked and unchecked methods of casting - so if at runtime if you are\nunsure what type a certain object is, you can try to cast it, which returns possible failure types like\n[`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) and\n[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).\n\nA common example of this in [`web-sys`](./web-sys.mdx) is when you are trying to get the\ntarget of an event. You might know what the target element is, but the\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API will always return an [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target).\nYou will need to cast it to the element type so you can call its methods.\n\n```rust\n// need to import the trait.\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // maybe the target is a select element?\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // do something amazing here\n        return;\n    }\n\n    // if it wasn't a select element then I KNOW it's a input element!\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\nThe [`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref)\nmethod is a checked cast that returns an `Option<&T>`, which means the original type\ncan be used again if the cast failed and thus returned `None`. The\n[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nmethod will consume `self`, as per convention for `into` methods in Rust, and the type returned is\n`Result<T, Self>`. If the casting fails, the original `Self` value is returned in `Err`. You can try again\nor do something else with the original type.\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\nThe `Closure` type provides a way to transfer Rust closures to JavaScript. The closures passed to\nJavaScript must have a `'static` lifetime for soundness reasons.\n\nThis type is a \"handle\" in the sense that whenever it is dropped, it will invalidate the JS\nclosure that it refers to. Any usage of the closure in JS after the Closure has been dropped will\nraise an exception.\n\n`Closure` is often used when you are working with a `js-sys` or `web-sys` API that accepts a type\n[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html).\nAn example of using a `Closure` in Yew can be found in the [Using `Closure` section](../html/events.mdx#using-closure-verbose)\non the [Events](../html/events.mdx) page.\n\n_[`Closure` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\nThe `js-sys` crate provides bindings/imports of JavaScript's standard, built-in objects, including\ntheir methods and properties.\n\nThis does not include any web APIs; that's what [`web-sys`](./web-sys.mdx) is for!\n\n_[`js-sys` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\nThe `wasm-bindgen-futures` crate provides a bridge for working with JavaScript Promise types as a\nRust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html), and contains\nutilities to turn a rust Future into a JavaScript Promise. This can be useful when working with\nasynchronous or otherwise blocking work in Rust (wasm), and provides the ability to interoperate\nwith JavaScript events and JavaScript I/O primitives.\n\nThere are three main interfaces in this crate currently:\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   A type that is constructed with a [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html)\n   and can then be used as a `Future<Output=Result<JsValue, JsValue>>`. This `Future` will resolve to `Ok` if\n   the `Promise` is resolved and `Err` if the `Promise` is rejected, containing the resolved or rejected\n   value from the `Promise` respectively.\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Converts a Rust `Future<Output=Result<JsValue, JsValue>>` into a\n   JavaScript `Promise`. The future’s result will translate to either a resolved or rejected\n   `Promise` in JavaScript.\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   Spawns a `Future<Output = ()>` on the current thread. This is the best way\n   to run a Future in Rust without sending it to JavaScript.\n\n_[`wasm-bindgen-futures` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` is going to be the most commonly used part of the `wasm-bindgen-futures` crate in Yew\nas this helps when using libraries that have async APIs.\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // console log \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew has also added support for futures in certain APIs, most notably you can create a\n`callback_future` which accepts an `async` block - this uses `spawn_local` internally.\n\n_[`spawn_local` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'The web-sys crate provides bindings for Web APIs.'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs. This is\nprocedurally generated from browser WebIDL which is why some names are so long and why some types are vague.\n\n## Features in `web-sys`\n\nThe `web-sys` crate with all of its features enabled can add lots of bloat to a Wasm application.\nTo get around this issue most types are feature gated so that you only include the types\nyou require for your application. Yew enables several features from `web-sys` and\nexposes some types in its public API. You will often need to add `web-sys` as a dependency yourself.\n\n## Inheritance in `web-sys`\n\nIn the [Simulating inheritance section](./wasm-bindgen.mdx#simulating-inheritance) you can read how in\ngeneral Rust provides an approach to simulate inheritance in JavaScript. This is very important in\n`web-sys` as understanding what methods are available on a type means understanding its inheritance.\n\nThis section is going to look at a specific element and list out its inheritance using Rust by\ncalling [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) until\nthe value is [`JsValue`](./wasm-bindgen.mdx#jsvalue):\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement is <textarea> in html.\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // Notice we have moved from web-sys types now into built-in\n    // JavaScript types which are in the js-sys crate.\n    let object: &js_sys::Object = event_target.deref();\n\n    // Notice we have moved from js-sys type to the root JsValue from\n    // the wasm-bindgen crate.\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // Using deref like this means we have to manually traverse\n    // the inheritance tree, however, you can call JsValue methods\n    // on the HtmlTextAreaElement type.\n    // The `is_string` method comes from JsValue.\n    assert!(!text_area.is_string());\n\n    // empty function just to prove we can pass HtmlTextAreaElement as a\n    // &EventTarget.\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // The compiler will walk down the deref chain in order to match the types here.\n    this_function_only_takes_event_targets(&text_area);\n\n    // The AsRef implementations allow you to treat the HtmlTextAreaElement\n    // as an &EventTarget.\n\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[Inheritance in `web-sys` in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)._\n\n## The `Node` in `NodeRef`\n\nYew uses a [`NodeRef`](concepts/function-components/node-refs.mdx) to provide a way for keeping a reference to\na `Node` made by the [`html!`](concepts/html/introduction.mdx) macro. The `Node` part of `NodeRef` is referring to\n[`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html). The\n`NodeRef::get` method will return a `Option<Node>` value, however, most of the time in Yew you want\nto cast this value to a specific element so you can use its specific methods. This casting\ncan be done using [`JsCast`](./wasm-bindgen.mdx#JsCast) on the `Node` value, if present, but Yew\nprovides the `NodeRef::cast` method to perform this casting for convenience and so that you do not\nnecessarily have to include the `wasm-bindgen` dependency for the `JsCast` trait.\n\nThe two code blocks below do essentially the same thing, the first is using `NodeRef::cast` and\nthe second is using [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\non the `web_sys::Node` returned from `NodeRef::get`.\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript example to Rust\n\nThis section demonstrates examples of how JavaScript code which interact with the\nWeb APIs can be rewritten with `web-sys` in Rust.\n\n### JavaScript example\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e = Mouse event.\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left //x position within the element.\n    var y = e.clientY - rect.top //y position within the element.\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` example\n\nUsing `web-sys` alone the above JavaScript example could be implemented like this:\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable all the web-sys features we want to use!\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// we now need to save the `mousemove` Closure so that when\n// this event fires the closure is still in memory.\n```\n\nThis version is much more verbose, but you will probably notice part of that is because of failure\ntypes reminding us that some of these function calls have invariants that must be held, or otherwise will\ncause a panic in Rust. Another part of the verbosity is the calls to `JsCast` to cast into\ndifferent types so that you can call its specific methods.\n\n### Yew example\n\nIn Yew you will mostly be creating [`Callback`](concepts/function-components/callbacks.mdx)s to use in the\n[`html!`](concepts/html/introduction.mdx) macro so the example is going to use this approach instead of completely copying\nthe approach above:\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable the `DomRect` feature to use the\n# `get_bounding_client_rect` method.\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## External libraries\n\n`web-sys` is a raw binding to the Web API so it comes with some pain in Rust because it was not\ndesigned with Rust or even a strong type system in mind, this is where community crates\nprovide abstractions over `web-sys` to provide more idiomatic Rust APIs.\n\n_[External libraries page](/community/external-libs)_\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, function_component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[function_component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[function_component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[function_component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[function_component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[function_component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[function_component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[function_component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\nCallbacks are used to asynchronously communicate upwards the components tree and with other things like agents or the DOM during event handling.\nInternally their type is just an `Fn` wrapped in `Rc` to allow them to be cheaply cloned.\n\nThey have an `emit` function if you want to call them manually.\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\")); // call the callback\n// web_sys::console::log_1(&result.into()); // if uncommented will print \"Bye Bob\"\n```\n\n## Passing callbacks as props\n\nA common pattern in yew is to create a callback and pass it down as a prop.\n\n```rust\nuse yew::{function_component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// Then supply the prop\n#[function_component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM Events and Callbacks\n\nCallbacks are also used to hook into DOM events.\n\nFor example, here we define a callback that will be called when the user clicks the button:\n\n```rust\nuse yew::{function_component, html, Html, Properties, Callback};\n\n#[function_component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[function_component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // the field name `children` is important!\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n    // highlight-next-line\n            { props.children.clone() } // you can forward children like this\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'Communication between components'\n---\n\n## Parent to child messaging\n\nPass data as [props](./properties) that cause a re-render, this is the way to pass messages to children.\n\n## Child to parent messaging\n\nPass down a callback via props, that the child on an event can call. [Example](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'Generic Components'\ndescription: 'The #[function_component] attribute'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `#[function_component]` attribute also works with generic functions for creating generic components.\n\n```rust\nuse std::fmt::Display;\nuse yew::{function_component, html, Properties, Html, ToHtml};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[function_component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + ToHtml,\n{\n    html! {\n        <p>\n            { &props.data }\n        </p>\n    }\n}\n\n// then can be used like this\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// or\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'Custom Hooks'\n---\n\n## Defining custom Hooks\n\nThe stateful logic of a component can be extracted into reusable functions by creating custom Hooks.\n\nConsider that we wish to create an event listener that listens to an event on the `window`\nobject.\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[function_component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nThere's one problem with this code: the logic can't be reused by another component.\nIf we build another component that listens to a different event,\ninstead of copying the code, we can move the logic into a custom hook.\n\nWe'll start by creating a new function called `use_event`.\nThe `use_` prefix denotes that a function is a hook.\nThis function will take an event target, an event type, and a callback.\nAll hooks must be marked by `#[hook]` on their function definition.\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nThis simple hook can be created by composing built-in hooks. For this example, we'll use the\n`use_effect_with` hook, so an event listener can be recreated when the hook arguments change.\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nAlthough this approach works in almost all cases, it can't be used to write primitive hooks like the pre-defined hooks we've been using already.\n\nView the docs on [docs.rs](https://docs.rs/yew) for documentation and `hooks` directory to see implementations of pre-defined hooks.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks are functions that let you store state and perform side effects.\n\nYew comes with a few pre-defined hooks. You can also create your own or discover many [community-made hooks](/community/awesome#hooks).\n\n## Rules of hooks\n\n1. A hook function name always has to start with `use_`\n2. Hooks can only be used in the following locations:\n    - Top-level of a function/hook.\n    - Blocks inside a function/hook, given it is not already branched.\n    - In the condition of a top-level `if` expression inside a function/hook.\n    - In the scrutinee of a top-level `match` expression inside a function/hook.\n3. Hooks must be called in the same order for every render. Returning early is only allowed when using [Suspense](../../suspense.mdx)\n\nThese rules are enforced by either compile-time or run-time errors.\n\n### Pre-defined Hooks\n\nYew comes with the following predefined Hooks:\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nThe documentation for these hooks can be found in the [Yew API docs](https://yew-rs-api.web.app/next/yew/functional/)\n\n### Custom Hooks\n\nThere are cases where you want to define your own Hooks to encapsulate potentially stateful logic from a component into reusable functions.\nSee the [Defining custom hooks](concepts/function-components/hooks/custom-hooks.mdx#defining-custom-hooks) section for more information.\n\n## Further reading\n\n- The React documentation has a section on [React hooks](https://reactjs.org/docs/hooks-intro.html).\n  These are not the same as Yew's hooks, but the underlying concept is similar.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[function_component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{function_component, html, Html};\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[function_component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'Node Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` attribute can be used to attach the `NodeRef` to an HTML element. In callbacks,\nyou can then get the DOM `Element` that the ref is attached to. This can be used to make\nchanges to the DOM outside of the `view` lifecycle method, retrieve the value of an `<input>`\nand other direct interactions with the DOM via the javascript API.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\n\n:::caution\nDo not manually modify the DOM tree that is rendered by Yew. Treat the `NodeRef` as a read-only\naccess, if you are unsure.\n:::\n\n## Further Reading\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` example](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nProperties are often shortened as \"Props\".\n\n:::\n\nProperties are essentially component arguments that Yew can keep watch on.\n\nA type has to implement the `Properties` trait before it can be used as the properties of a component.\n\n## Reactivity\n\nYew checks if props have changed when reconciling the Virtual DOM during re-rendering, to know if nested components need to be re-rendered.\nThis way Yew can be considered a very reactive framework, as changes from the parent will always be propagated downward,\nand the view will never be out of sync with the data coming from props/state.\n\n:::tip\n\nIf you have not yet completed the [tutorial](../../tutorial), try it out and test this reactivity yourself!\n\n:::\n\n## Derive macro\n\nYew provides a derive macro to easily implement the `Properties` trait on structs.\n\nTypes for which you derive `Properties` must also implement `PartialEq` so Yew can do data comparison.\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## Use in function components\n\nThe attribute `#[function_component]` allows to optionally receive Props in the function arguments. To supply them,\nthey are assigned via attributes in the `html!` macro.\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{props.is_loading.clone()}</> }\n}\n\n// Then supply the prop\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{function_component, html, Html};\n\n\n\n\n\n\n#[function_component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// No props to supply\n#[function_component]\nfn App() -> Html {\n    html! {<HelloWorld />}\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## Derive macro field attributes\n\nWhen deriving `Properties` all fields are required by default.\nThe following attributes allow you to give your props default values which will be used when the parent has not set them.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading.clone() {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// Then use like this with default\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// Or no override the default\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld is_loading={true} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`. The expression\nis evaluated when the properties are constructed and no explicit value has been given.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or(\"Bob\".to_string())]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// Then use like this with default\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// Or no override the default\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\nThe function is called when no explicit value has been given for that attribute.\n\n```rust\nuse yew::{function_component, html, Html, Properties};\n\nfn create_default_name() -> String {\n    \"Bob\".to_string()\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: String,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n// Then use like this with default\n#[function_component]\nfn Case1() -> Html {\n    html! {<HelloWorld />}\n}\n// Or no override the default\n#[function_component]\nfn Case2() -> Html {\n    html! {<HelloWorld name={\"Sam\".to_string()} />}\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a shared pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or(AttrValue::from(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {<>{\"Hello world\"}{props.name.clone()}</>}\n}\n\n#[function_component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = props! {\n        Props {} // Notice we did not need to specify name prop\n    };\n    // highlight-end\n    html! {<HelloWorld ..pre_made_props />}\n}\n```\n\n## Evaluation Order\n\nProps are evaluated in the order they're specified, as shown by the following example:\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nfn main() {\n    let mut g = 1..=3;\n    let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\n    assert_eq!(props.first, 1);\n    assert_eq!(props.second, 2);\n    assert_eq!(props.last, 3);\n}\n```\n\n## Anti Patterns\n\nWhile almost any Rust type can be passed as properties, there are some anti-patterns that should be avoided.\nThese include, but are not limited to:\n\n1. Using `String` type instead of `AttrValue`. <br />\n   **Why is this bad?** `String` can be expensive to clone.\n   Cloning is often needed when the prop value is used with hooks and callbacks. `AttrValue` is either\n   a reference-counted string (`Rc<str>`) or a `&'static str`, thus very cheap to clone.<br />\n   **Note**: `AttrValue` internally is `IString` from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n2. Using interior mutability. <br />\n   **Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should\n   _generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when the state has changed)\n   so you may have to manually force a render. Like all things, it has its place. Use it with caution.\n3. Using `Vec<T>` type instead of `IArray<T>`. <br />\n   **Why is this bad?** `Vec<T>`, just like `String`, can also be expensive to clone. `IArray<T>` is either\n   a reference-counted slice (`Rc<[T]>`) or a `&'static [T]`, thus very cheap to clone.<br />\n   **Note**: `IArray<T>` can be imported from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n4. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue\n   or PR a fix to this documentation.\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) is an experimental package that allows one to create the Props struct on the fly out of the arguments of your function. Might be useful, if the properties struct is never reused.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: 'Pure Components'\n---\n\nA function component is considered [pure] when the returned `Html` is deterministically derived\nfrom its props when its view function does not mutate its state or has other side effects.\n\n[pure]: https://en.wikipedia.org/wiki/Pure_function\n\nThe example below is a pure component. For a given prop `is_loading` it will always result in the same `Html` without any side effects.\n\n```rust\nuse yew::{Properties, function_component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[function_component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\nIf you have an internal pure component that makes no use of hooks and other component machinery, you can often write it instead\nas a normal function returning `Html` and avoid a bit of overhead for Yew, related to running the component lifecycle. Use\n[expression syntax](concepts/html/literals-and-expressions.mdx#expressions) to render them in `html!`.\n:::\n\n## Impure components\n\nYou might wonder if a component can be impure if it does not use any globals, since it is just a function that is called every render.\nThis is where the next topic comes in - [hooks](./hooks)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/function-components/state.mdx",
    "content": "---\ntitle: 'State'\n---\n\n## General view of how to store state\n\nThis table can be used as a guide when deciding what state-storing type fits best for your use case:\n\n| Hook                     | Type                       | Rerender when?               | Scope               |\n| ------------------------ | -------------------------- | ---------------------------- | ------------------- |\n| [use_state]              | `T`                        | got set                      | component instance  |\n| [use_state_eq]           | `T: PartialEq`             | got set with diff. value     | component instance  |\n| [use_reducer]            | `T: Reducible`             | got reduced                  | component instance  |\n| [use_reducer_eq]         | `T: Reducible + PartialEq` | got reduced with diff. value | component instance  |\n| [use_memo]               | `Deps -> T`                | dependencies changed         | component instance  |\n| [use_callback]           | `Deps -> Callback<E>`      | dependencies changed         | component instance  |\n| [use_mut_ref]            | `T`                        | -                            | component instance  |\n| a static global variable | `T`                        | -                            | global, used by all |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/classes.mdx",
    "content": "---\ntitle: 'Classes'\ndescription: 'A handy macro to handle classes'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Classes\n\nThe struct `Classes` can be used to deal with HTML classes.\n\nWhen pushing a string to the set, `Classes` ensures that there is one element\nfor every class even if a single string might contain multiple classes.\n\n`Classes` can also be merged by using `Extend` (i.e.\n`classes1.extend(classes2)`) or `push()` (i.e. `classes1.push(classes2)`).\nAny type that implements `Into<Classes>` can be pushed onto an existing `Classes`.\n\nThe macro `classes!` is a convenient macro that creates one single `Classes`.\nIts input accepts a comma-separated list of expressions. The only requirement\nis that every expression implements `Into<Classes>`.\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Components that accept classes\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[function_component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/components.mdx",
    "content": "---\ntitle: 'Components'\ndescription: 'Create complex layouts with component hierarchies'\n---\n\n## Basic\n\nComponents can be used in the `html!` macro:\n\n```rust\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[function_component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // With the whole set of props provided at once\n        <MyComponentWithProps ..props.clone() />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## Nested\n\nComponents can accept child components/elements if they have a `children` field in their `Properties`\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[function_component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\nThe `html!` macro allows you to pass a base expression with the `..props` syntax instead of specifying each property individually,\nsimilar to Rust's [Functional Update Syntax](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax).\nThis base expression must occur after any individual props are passed.\nWhen passing a base props expression with a `children` field, the children passed in the `html!` macro overwrite the ones already present in the props.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[function_component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // props.children will be overwritten with this\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## Relevant examples\n\n- [Function Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [Function Router](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: 'Conditional rendering'\ndescription: 'Rendering nodes conditionally in html!'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If blocks\n\nTo conditionally render some markup, we wrap it in an `if` block:\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/elements.mdx",
    "content": "---\ntitle: 'Elements'\ndescription: 'Both HTML and SVG elements are supported'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM nodes\n\nThere are many reasons why you might want to create or manage DOM nodes manually in Yew, such as\nwhen integrating with JS libraries that can cause conflicts with managed components.\n\nUsing `web-sys`, you can create DOM elements and convert them into a `Node` - which can then be\nused as an `Html` value using `VRef`:\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[function_component]\nfn MyComponent() -> Html {\n    // memoize as this only needs to be executed once\n    let node = use_memo(\n        (),\n        |_| {\n            // Create a div element from the document\n            let div: Element = document().create_element(\"div\").unwrap();\n            // Add content, classes etc.\n            div.set_inner_html(\"Hello, World!\");\n            // Convert Element into a Node\n            let node: Node = div.into();\n            // Return that Node as a Html value\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo return Rc so we need to deref and clone\n    (*node).clone()\n}\n\n```\n\n## Dynamic tag names\n\nWhen building a higher-order component you might find yourself in a situation where the element's tag name is not static.\nFor example, you might have a `Title` component that can render anything from `h1` to `h6` depending on a level prop.\nInstead of having to use a big match expression, Yew allows you to set the tag name dynamically\nusing `@{name}` where `name` can be any expression that returns a string.\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## Boolean Attributes\n\nSome content attributes (e.g checked, hidden, required) are called boolean attributes. In Yew,\nboolean attributes need to be set to a bool value:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nThis will result in **HTML** that is functionally equivalent to this:\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\nSetting a boolean attribute to false is equivalent to not using the attribute at all; values from\nboolean expressions can be used:\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nThis will result in the following **HTML**:\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## String-like attributes\n\nBut apart from a select few boolean attributes, you will probably be dealing with a lot of string-like HTML attributes and Yew has a few options to pass string-like values to components.\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nThey are all valid **but** we encourage you to favor Yew's custom `AttrValue`, especially if you need to clone or pass them as properties to another component.\n\n## Optional attributes for HTML elements\n\nMost HTML attributes can use optional values (Some(x) or None). This allows us to omit the attribute if the attribute is marked as optional.\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\nIf the attribute is set to `None`, the attribute will not be set in the DOM.\n\n## Relevant examples\n\n- [Inner HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/events.mdx",
    "content": "---\ntitle: 'Events'\n---\n\n## Introduction\n\nYew integrates with the [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate and\nuses the events from that crate. The [table below](#event-types) lists all of the `web-sys`\nevents that are accepted in the `html!` macro.\n\nYou can still add a [`Callback`](../function-components/callbacks.mdx) for an event that is not listed in the table\nbelow, see [Manual event listener](#manual-event-listener).\n\n## Event Types\n\n:::tip\nAll the event types mentioned in the following table are re-exported under `yew::events`.\nUsing the types from `yew::events` makes it easier to ensure version compatibility than\nif you were to manually include `web-sys` as a dependency in your crate because you will not\nend up using a version which conflicts with the version that Yew specifies.\n:::\n\nThe event listener name is the expected name when adding an event `Callback` in the `html` macro:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nThe event name is the listener without the \"on\" prefix, therefore, the `onclick` event listener\nlistens for `click` events. See the end of this page for a [full list of available event](#available-events) with their types.\n\n## Event bubbling {#event-bubbling}\n\nEvents dispatched by Yew follow the virtual DOM hierarchy when bubbling up to listeners. Currently, only the bubbling phase\nis supported for listeners. Note that the virtual DOM hierarchy is most often, but not always, identical to the actual\nDOM hierarchy. The distinction is important when working with [portals](../../advanced-topics/portals) and other\nmore advanced techniques. The intuition for well-implemented components should be that events bubble from children\nto parents. In this way the hierarchy in your coded `html!` is the one observed by event handlers.\n\nIf you are not interested in event bubbling, you can turn it off by calling\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n_before_ starting your app. This speeds up event handling, but some components may break from not receiving the events they expect.\nUse this with care!\n\n## Event delegation\n\nIt can be surprising that event listeners are _not_ directly registered on the element where they are rendered. Instead, events\nare delegated from the subtree root of the Yew app. Still, events are delivered in their native form, and no synthetic\nform is created. This can lead to mismatches between the event you would expect in HTML listeners and those showing up in Yew.\n\n- [`Event::current_target`] points to the Yew subtree root instead of the element the listener is added on. Use\n  [`NodeRef`](../function-components/node-refs.mdx) if you want access to the underlying `HtmlElement`.\n- [`Event::event_phase`] is always [`Event::CAPTURING_PHASE`]. Internally, the event will behave as if it was in the bubbling\n  phase, the event propagation is replayed and the event [bubbles _up_](#event-bubbling), i.e. event listeners higher up in\n  the virtual DOM will trigger _after_ event listeners below them. Currently, capturing listeners is not supported by Yew.\n\n    This also means that events registered by Yew will usually fire before other event listeners.\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## Typed event target\n\n:::caution\nIn this section **target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))**\nis always referring to the element at which the event was dispatched from.\n\nThis will **not** always be the element at which the `Callback` is placed.\n:::\n\nIn event `Callback`s you may want to get the target of that event. For example, the\n`change` event gives no information but is used to notify that something has changed.\n\nIn Yew getting the target element in the correct type can be done in a few ways and we will go through\nthem here. Calling [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)\non an event returns an optional [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html)\ntype, which might not seem very useful when you want to know the value of your input element.\n\nIn all the approaches below we are going to tackle the same problem, so it is clear where the approach\ndiffers as opposed to the problem at hand.\n\n**The Problem:**\n\nWe have an `onchange` `Callback` on my `<input>` element and each time it is invoked we want to send\nan [update](components#update) `Msg` to our component.\n\nOur `Msg` enum looks like this:\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### Using `JsCast`\n\nThe [`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate has\na useful trait; [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nwhich allows us to hop and skip our way to the type we want, as long as it implements `JsCast`. We can\ndo this cautiously, which involves some runtime checks and failure types like `Option` and `Result`,\nor we can do it dangerously.\n\nEnough talk, more code:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# need wasm-bindgen for JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // When events are created the target is undefined, it's only\n            // when dispatched does the target get added.\n            let target: Option<EventTarget> = e.target();\n            // Events can bubble so this listener might catch events from child\n            // elements which are not of type HtmlInputElement\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        // Here we are sure that this is input element so we can convert it to the appropriate type without checking\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nThe methods from `JsCast` are [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nand [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)\nand you can probably see, they allowed\nus to go from `EventTarget` to [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html).\nThe `dyn_into` method is cautious because at\nruntime it will check whether the type is actually a `HtmlInputElement` and if not return an\n`Err(JsValue)`, the [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\nis a catch-all type and is essentially giving you back the object to try again.\n\nAt this point you might be thinking... when is the dangerous version ok to use? In the case above it\nis safe<sup>1</sup> as we've set the `Callback` on to an element with no children so the target can\nonly be that same element.\n\n_<sup>1</sup> As safe as anything can be when JS land is involved._\n\n### Using `TargetCast`\n\n**It is highly recommended to read [Using JsCast](#using-jscast) first!**\n\n:::note\n`TargetCast` was designed to feel very similar to `JsCast` - this is to allow new users to get a feel\nfor the behaviour of `JsCast` but with the smaller scope of events and their targets.\n\n`TargetCast` vs `JsCast` is purely preference, you will find that `TargetCast` implements something\nsimilar to what you would using `JsCast`.\n:::\n\nThe `TargetCast` trait is built on top of `JsCast` and is specialized towards getting typed event\ntargets from events.\n\n`TargetCast` comes with Yew so no need to add a dependency in order to use the trait methods on events\nbut it works in a very similar way to `JsCast`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nIf you followed the advice above and read about `JsCast`, or know the trait, you can probably\nsee that `TargetCast::target_dyn_into` feels similar to `JsCast::dyn_into` but specifically\ndoes the cast on the target of the event. `TargetCast::target_unchecked_into` is similar to\n`JsCast::unchecked_into`, and as such all the same warnings above `JsCast` apply to `TargetCast`.\n\n### Using `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) can be used instead of querying the event given to a `Callback`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nUsing `NodeRef`, you can ignore the event and use the `NodeRef::cast` method to get an\n`Option<HtmlInputElement>` - this is optional as calling `cast` before the `NodeRef` has been\nset, or when the type doesn't match will return `None`.\n\nYou might also see by using `NodeRef` we don't have to send the `String` back into state as we always access to `input_node_ref` - so we could do the following:\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // do something with value\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nWhich approach you take depends on your component and your preferences, there is no _blessed_ way\nper se.\n\n## Manual event listener\n\nYou may want to listen to an event that is not supported by Yew's `html` macro, see the\n[supported events listed here](#event-types).\n\nIn order to add an event listener to one of elements manually we need the help of\n[`NodeRef`](../function-components/node-refs.mdx) so that in `use_effect_with` we can add a listener using the\n[`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) and\n[wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API.\n\nThe examples below are going to show adding listeners for the made-up `custard` event. All events\neither unsupported by yew or custom can be represented as a\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html). If you\nneed to access a specific method or field on a custom / unsupported event then you can use the\nmethods of [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nin order to convert to the type required.\n\n### Using `Closure` (verbose)\n\nUsing the `web-sys` and `wasm-bindgen` API's directly for this can be a bit painful.. so brace\nyourself ([there is a more concise way thanks to `gloo`](#using-gloo-concise)).\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `Closures`, see\n[The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html).\n\n### Using `gloo` (concise)\n\nThe easier way is with `gloo`, more specifically [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)\nwhich is an abstraction for `web-sys`, `wasm-bindgen`.\n\n`gloo_events` has the `EventListener` type which can be used to create and store the\nevent listener.\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[function_component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `EventListener`, see the\n[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html).\n\n## Full list of available events {#available-events}\n\n| Event listener name         | `web_sys` Event Type                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/fragments.mdx",
    "content": "---\ntitle: 'Fragments'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro always requires a single root node. To get around this restriction, you\ncan use an \"empty tag\" (these are also called \"fragments\").\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// error: only one root html element allowed\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'The procedural macro for generating HTML and SVG'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro allows you to write HTML and SVG code declaratively. It is similar to JSX\n(an extension to JavaScript that allows you to write HTML-like code inside of JavaScript).\n\n**Important notes**\n\n1. The `html!` macro only accepts one root html node (you can counteract this by using\n   [fragments](./fragments.mdx) or [iterators](./../html/lists.mdx))\n2. An empty `html! {}` invocation is valid and will not render anything\n3. Literals must always be quoted and wrapped in braces: `html! { <p>{ \"Hello, World\" }</p> }`\n4. The `html!` macro will make all tag names lowercase. To use upper case characters (which are required for some SVG elements) use [dynamic tag names](concepts/html/elements.mdx#dynamic-tag-names): `html! { <@{\"myTag\"}></@> }`\n\n:::note\nThe `html!` macro can reach the default recursion limit of the compiler. If you encounter compilation errors,\nadd an attribute like `#![recursion_limit=\"1024\"]` in the crate root to overcome the problem.\n:::\n\n## Tag Structure\n\nTags are based on HTML tags. Components, Elements, and Lists are all based on this tag syntax.\n\nTags must either self-close `<... />` or have a corresponding end tag for each start tag.\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\nFor convenience, elements which _usually_ require a closing tag are **allowed** to self-close. For example, writing `html! { <div class=\"placeholder\" /> }` is valid.\n:::\n\n## Children\n\nCreate complex nested HTML and SVG layouts with ease:\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nIf you compile Yew using a nightly version of the Rust compiler, the macro will warn you about some\ncommon pitfalls that you might run into. Of course, you may need to use the stable compiler (e.g.\nyour organization might have a policy mandating it) for release builds, but even if you're using a\nstable toolchain, running `cargo +nightly check` might flag some ways that you could improve your\nHTML code.\n\nAt the moment the lints are mostly accessibility-related. If you have ideas for lints, please feel\nfree to [chime in on this issue](https://github.com/yewstack/yew/issues/1334).\n\n## Specifying attributes and properties\n\nAttributes are set on elements in the same way as in normal HTML:\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\nProperties are specified with `~` before the element name:\n\n```rust\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\nThe braces around the value can be omitted if the value is a literal.\n\n:::\n\n:::note What classifies as a literal\n\nLiterals are all valid [literal expressions](https://doc.rust-lang.org/reference/expressions/literal-expr.html)\nin Rust. Note that [negative numbers are **not** literals](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)\nand thus must be enclosed in curly-braces `{-6}`\n\n:::\n\n:::note Component properties\nComponent properties are passed as Rust objects and are different from the element attributes/properties described here.\nRead more about them at [Component Properties](../function-components/properties.mdx)\n:::\n\n### Special properties\n\nThere are special properties which don't directly influence the DOM but instead act as instructions to Yew's virtual DOM.\nCurrently, there are two such special props: `ref` and `key`.\n\n`ref` allows you to access and manipulate the underlying DOM node directly. See [Refs](../function-components/node-refs.mdx) for more details.\n\n`key` on the other hand gives an element a unique identifier which Yew can use for optimization purposes.\n\n:::info\nRead more at [Lists](./html/lists)\n:::\n\n## Conditional Rendering\n\nMarkup can be rendered conditionally by using Rust's conditional structures. ' +\n'Currently only `if` and `if let` are supported.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\nRead more at [Conditional Rendering](./conditional-rendering.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/lists.mdx",
    "content": "---\ntitle: 'Lists'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Iterators\n\nYew supports two different syntaxes for building HTML from an iterator.\n\n<Tabs>\n  <TabItem value=\"Syntax type 1\" label=\"Syntax type 1\">\n\nThe first is to call `collect::<Html>()` on the final transform in your iterator, which returns a\nlist that Yew can display.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Syntax type 2\" label=\"Syntax type 2\">\n\nThe alternative is to use the `for` keyword, which is not native Rust syntax and instead is used by\nthe HTML macro to output the needed code to display the iterator.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Keyed lists\n\nA keyed list is an optimized list that has keys on **all** children.\n`key` is a special prop provided by Yew that gives an HTML element or component a unique identifier\nthat is used for optimization purposes inside Yew.\n\n:::caution\nKey has to be unique only in each list, in contrast to the global uniqueness of HTML `id`s. It must not depend on the order of the list.\n:::\n\nIt is always recommended to add keys to lists.\n\nKeys can be added by passing a unique `String`, `str` or integer to the special `key` prop:\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### Performance increases\n\nWe have [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list) example that lets you test the performance improvements, but here is a rough rundown:\n\n1. Go to [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list) hosted demo\n2. Add 500 elements.\n3. Disable keys.\n4. Reverse the list.\n5. Look at \"The last rendering took Xms\" (At the time of writing this it was ~60ms)\n6. Enable keys.\n7. Reverse the list.\n8. Look at \"The last rendering took Xms\" (At the time of writing this it was ~30ms)\n\nSo just at the time of writing this, for 500 components it is a 2x increase of speed.\n\n### Detailed explanation\n\nUsually, you just need a key on every list item when you iterate and the order of data can change.\nIt's used to speed up the reconciliation process when re-rendering the list.\n\nWithout keys, assume you iterate through `[\"bob\", \"sam\", \"rob\"]`, ending up with the HTML:\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\nThen on the next render, if your list changed to `[\"bob\", \"rob\"]`, yew could delete\nthe element with id=\"rob\" and update id=\"sam\" to be id=\"rob\"\n\nIf you had added a key to each element, the initial HTML would be the same, but after\nthe render with the modified list, `[\"bob\", \"rob\"]`, yew would just delete the second\nHTML element and leave the rest untouched since it can use the keys to associate them.\n\nIf you ever encounter a bug/\"feature\" where you switch from one component to another but both have a div as the highest rendered element.\nYew reuses the rendered HTML div in those cases as an optimization.\nIf you need that div to be recreated instead of reused, then you can add different keys and they will not be reused.\n\n## Further reading\n\n- [TodoMVC](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'Literals and Expressions'\n---\n\n## Literals\n\nIf expressions resolve to types that implement `Display`, they will be converted to strings and inserted into the DOM as a [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) node.\n:::note\nString literals create `Text` nodes, which are treated as strings by the browser. Hence, even if the expression contains a `<script>` tag you can't fall for XSS and such security issues, unless of course you wrap the expression in a `<script>` block.\n:::\n\nAll display text must be enclosed by `{}` blocks because the text is handled as an expression. This is\nthe largest deviation from normal HTML syntax that Yew makes.\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## Expressions\n\nYou can insert expressions in your HTML using `{}` blocks, as long as they resolve to `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\nIt often makes sense to extract these expressions into functions or closures to optimize for readability:\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/router.mdx",
    "content": "---\ntitle: 'Router'\ndescription: \"Yew's official router\"\n---\n\nRouters in Single Page Applications (SPA) handle displaying different pages depending on what the URL is. Instead of the\ndefault behavior of requesting a different remote resource when a link is clicked, the router instead sets the URL\nlocally to point to a valid route in your application. The router then detects this change and then decides what to\nrender.\n\nYew provides router support in the `yew-router` crate. To start using it, add the dependency to your `Cargo.toml`\n\n<!-- Reminder: fix this when we release a new version of yew -->\n\n```toml\nyew-router = { git = \"https://github.com/yewstack/yew.git\" }\n```\n\nThe utilities needed are provided under `yew_router::prelude`,\n\n## Usage\n\nYou start by defining a `Route`.\n\nRoutes are defined as an `enum` which derives `Routable`. This enum must be `Clone + PartialEq`.\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\nA `Route` is paired with a `<Switch />` component, which finds the variant whose path matches the browser's\ncurrent URL and passes it to the `render` callback. The callback then decides what to render. In case no path is\nmatched, the router navigates to the path with `not_found` attribute. If no route is specified, nothing is rendered, and\na message is logged to the console stating that no route was matched.\n\nMost of yew-router's components, in particular `<Link />` and `<Switch />`, must be (grand-)children of one of the Router components\n(e.g. `<BrowserRouter />`). You usually only need a single Router in your app, most often rendered immediately by your most top-level `<App />`\ncomponent. The Router registers a context, which is needed for Links and Switches to function. An example is shown below.\n\n:::caution\nWhen using `yew-router` in a browser environment, `<BrowserRouter />` is highly recommended.\nYou can find other router flavors in the [API Reference](https://docs.rs/yew-router/).\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[function_component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[function_component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### Path Segments\n\nIt is also possible to extract information from a route using dynamic and named wildcard segments.\nYou can then access the post's id inside `<Switch />` and forward it to the appropriate component via properties.\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\nYou can have a normal `Post` variant instead of `Post {id: String}` too. For example, when `Post` is rendered\nwith another router, the field can then be redundant as the other router can match and handle the path. See the\n[Nested Router](#nested-router) section below for details\n:::\n\nNote the fields must implement `Clone + PartialEq` as part of the `Route` enum. They must also implement\n`std::fmt::Display` and `std::str::FromStr` for serialization and deserialization. Primitive types like integer, float,\nand String already satisfy the requirements.\n\nIn case when the form of the path matches, but the deserialization fails (as per `FromStr`). The router will consider\nthe route as unmatched and try to render the not found route (or a blank page if the not found route is unspecified).\n\nConsider this example:\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch function renders News and id as is. Omitted here.\n```\n\nWhen the segment goes over 255, `u8::from_str()` fails with `ParseIntError`, the router will then consider the route\nunmatched.\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\nFor more information about the route syntax and how to bind parameters, check\nout [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params).\n\n### Location\n\nThe router provides a universal `Location` struct via context which can be used to access routing information.\nThey can be retrieved by hooks or convenient functions on `ctx.link()`.\n\n### Navigation\n\n`yew_router` provides a handful of tools to work with navigation.\n\n#### Link\n\nA `<Link />` renders as an `<a>` element, the `onclick` event handler will call\n[preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault), and push the targeted page to the\nhistory and render the desired page, which is what should be expected from a Single Page App. The default `onclick` of a\nnormal anchor element would reload the page.\n\nThe `<Link />` component also passes its children to the `<a>` element. Consider it a replacement of `<a/>` for in-app\nroutes. Except you supply a `to` attribute instead of a `href`. An example usage:\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\nStruct variants work as expected too:\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew v0.19 out now!\" }</Link<Route>>\n```\n\n#### Navigator API\n\nNavigator API is provided for both function components and struct components. They enable callbacks to change the\nroute. A `Navigator` instance can be obtained in either case to manipulate the route.\n\n##### Function Components\n\nFor function components, the `use_navigator` hook re-renders the component when the underlying navigator provider changes.\nHere is how to implement a button that navigates to the `Home` route when clicked.\n\n```rust ,ignore\n#[function_component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\nThe example here uses `Callback::from`. Use a normal callback if the target route can be the same as the route\nthe component is in, or just to play safe. For example, consider a logo button on every page that goes back to the\nhome page when clicked. Clicking that button twice on the home page causes the code to panic because the second click pushes an\nidentical Home route and the `use_navigator` hook will not trigger a re-render.\n:::\n\nIf you want to replace the current location instead of pushing a new location onto the stack, use `navigator.replace()`\ninstead of `navigator.push()`.\n\nYou may notice `navigator` has to move into the callback, so it cannot be used again for other callbacks. Luckily `navigator`\nimplements `Clone`, here is for example how to have multiple buttons for different routes:\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[function_component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### Struct Components\n\nFor struct components, the `Navigator` instance can be obtained through the `ctx.link().navigator()` API. The rest is\nidentical to the function component case. Here is an example of a view function that renders a single button.\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### Redirect\n\n`yew-router` also provides a `<Redirect />` component in the prelude. It can be used to achieve similar effects as the\nnavigator API. The component accepts a\n`to` attribute as the target route. When a `<Redirect/>` is rendered users will be redirected to the route specified in props.\nHere is an example:\n\n```rust ,ignore\n#[function_component(SomePage)]\nfn some_page() -> Html {\n    // made-up hook `use_user`\n    let user = match use_user() {\n        Some(user) => user,\n        // Redirects to the login page when user is `None`.\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... actual page content.\n}\n```\n\n:::tip `Redirect` vs `Navigator`, which to use\nThe Navigator API is the only way to manipulate route in callbacks.\nWhile `<Redirect />` can be used as return values in a component. You might also want to use `<Redirect />` in another\nnon-component context, for example in the switch function of a [Nested Router](#nested-router).\n:::\n\n### Listening to Changes\n\n#### Function Components\n\nYou can use `use_location` and `use_route` hooks. Your components will re-render when\nprovided values change.\n\n#### Struct Components\n\nIn order to react on route changes, you can pass a callback closure to the `add_location_listener()` method of `ctx.link()`.\n\n:::note\nThe location listener will get unregistered once it is dropped. Make sure to store the handle inside your\ncomponent state.\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // handle event\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` and `ctx.link().route::<R>()` can also be used to retrieve the location and the route once.\n\n### Query Parameters\n\n#### Specifying query parameters when navigating\n\nIn order to specify query parameters when navigating to a new route, use either `navigator.push_with_query` or\nthe `navigator.replace_with_query` functions. It uses `serde` to serialize the parameters into a query string for the URL so\nany type that implements `Serialize` can be passed. In its simplest form, this is just a `HashMap` containing string\npairs.\n\n#### Obtaining query parameters for the current route\n\n`location.query` is used to obtain the query parameters. It uses `serde` to deserialize the parameters from the query string\nin the URL.\n\n## Nested Router\n\nNested router can be useful when the app grows larger. Consider the following router structure:\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nThe nested `SettingsRouter` handles all URLs that start with `/settings`. Additionally, it redirects URLs that are not\nmatched to the main `NotFound` route. So `/settings/gibberish` will redirect to `/404`.\n\n:::caution\n\nThough note that this is still a work in progress so the way we do this is not final\n\n:::\n\nIt can be implemented with the following code:\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[function_component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### Basename\n\nIt's possible to define a basename with `yew-router`.\nA basename is a common prefix of all routes. Both the Navigator API and\n`<Switch />` component respect basename setting. All pushed routes will be\nprefixed with the basename and all switches will strip the basename before\ntrying to parse the path into a `Routable`.\n\nIf a basename prop is not supplied to the Router component, it will use\nthe href attribute of the `<base />` element in your HTML file and\nfallback to `/` if no `<base />` is present in the HTML file.\n\n## Relevant examples\n\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## API Reference\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/concepts/suspense.mdx",
    "content": "---\ntitle: 'Suspense'\ndescription: 'Suspense for data fetching'\n---\n\nSuspense is a way to suspend component rendering whilst waiting a task\nto complete and a fallback (placeholder) UI is shown in the meanwhile.\n\nIt can be used to fetch data from server, wait for tasks to be completed\nby an agent, or perform other background asynchronous task.\n\nBefore suspense, data fetching usually happens after (Fetch-on-render) or before\ncomponent rendering (Fetch-then-render).\n\n### Render-as-You-Fetch\n\nSuspense enables a new approach that allows components to initiate data request\nduring the rendering process. When a component initiates a data request,\nthe rendering process will become suspended and a fallback UI will be\nshown until the request is completed.\n\nThe recommended way to use suspense is with hooks.\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[function_component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[function_component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\nIn the above example, the `use_user` hook will suspend the component\nrendering while user information is loading and a `Loading...` placeholder will\nbe shown until `user` is loaded.\n\nTo define a hook that suspends a component rendering, it needs to return\na `SuspensionResult<T>`. When the component needs to be suspended, the\nhook should return a `Err(Suspension)` and users should unwrap it with\n`?` in which it will be converted into `Html`.\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### Note on implementing suspending hooks\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) returns 2 values: the suspension context itself, and a suspension handle.\nThe latter is the one responsible for signaling when to re-render the suspended components, it provides 2 interchangeable ways to do so:\n\n1. Calling its [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) method.\n2. Dropping the handle.\n\n:::danger\n\nThe suspension handle must be stored until it's time to update components, i.e. with newly received data;\notherwise, the suspended components will enter an infinite re-render loop, thus hampering performance.\nIn the example above, the suspension handle is preserved by being moved into a closure and passed into `on_load_user_complete`.\nWhen the hypothetical user will be loaded, the closure will be called, thus calling `handle.resume()` and re-rendering the components associated with the suspension context.\n\n:::\n\n# Complete Example\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // implementation omitted.\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // implementation omitted.\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[function_component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[function_component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### Use Suspense in Struct Components\n\nIt's not possible to suspend a struct component directly. However, you\ncan use a function component as a [Higher Order Component](../advanced-topics/struct-components/hoc)\nto achieve suspense-based data fetching.\n\nThe [suspense example in the Yew repository](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)\ndemonstrates how to use.\n\n## Relevant examples\n\n- [Suspense](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'Build a sample app'\n---\n\nOnce you have the environment ready, you can either choose to use a starter template that contains\nthe boilerplate needed for a basic Yew app or manually set up a small project.\n\n## Using a starter template\n\nInstall [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) by following their installation instructions\nthen take the following steps:\n\n### Checkout and customize project\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n### Run project\n\n```shell\ntrunk serve\n```\n\n:::note\n\nTrunk [has a bug](https://github.com/trunk-rs/trunk/issues/852) on windows when `trunk serve` command fails. To workaround the issue you can run `trunk build` before running `trunk serve`.\n\n:::\n\n## Setting up the application manually\n\n### Create Project\n\nTo get started, create a new cargo project.\n\n```bash\ncargo new yew-app\n```\n\nOpen the newly created directory.\n\n```bash\ncd yew-app\n```\n\n### Run a hello world example\n\nTo verify the Rust environment is set up, run the initial project using `cargo run`. You should see\na \"Hello World!\" message.\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### Setting up the project as a Yew web application\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\n\n#### Update Cargo.toml\n\nAdd `yew` to the list of dependencies.\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.21\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n#### Update main.rs\n\nWe need to generate a template that sets up a root Component called `App` which renders a button\nthat updates its value when clicked. Replace the contents of `src/main.rs` with the following code.\n\n:::note\nThe call to `yew::Renderer::<App>::new().render()` inside the `main` function starts your application and mounts\nit to the page's `<body>` tag. If you would like to start your application with any dynamic\nproperties, you can instead use `yew::Renderer::<App>::with_props(..).render()`.\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[function_component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### Create index.html\n\nFinally, add an `index.html` file in the root directory of your app.\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## View your web application\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve\n```\n\n:::info\nAdd option '--open' to open your default browser `trunk serve --open`.\n:::\n\nTrunk will rebuild your application if you modify any of its source code files.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\n## Congratulations\n\nYou have now successfully set up your Yew development environment, and built your first web application.\n\nExperiment with this application and review the [examples](./examples.mdx) to further your learning.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'Editor Setup'\ndescription: 'Setting your code editor'\n---\n\n:::important contribute\nUsing a different editor? Feel free to add instructions for your editor of choice.\n:::\n\n## Add a template for creating components\n\n### JetBrains IDEs\n\n1. Navigate to File | Settings | Editor | Live Templates.\n2. Select Rust and click on the + icon to add a new Live Template.\n3. Give it a name and description of your preference.\n4. Paste the following snippet(s) into the Template Text section.\n5. Change the applicability on the lower right, select Rust > Item > Module\n\nFor function components, use the following template.\n\n- (Optional) Click on Edit Variable and give `tag` a reasonable default value like \"div\", with double quotes.\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[function_component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\nFor struct components, you can use the following more complicated template.\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. Navigate to File > Preferences > User Snippets.\n2. Select Rust as the language.\n3. Add the following snippet in the snippet JSON file:\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[function_component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## Support for the `html!` Macro\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew extension\n\n> 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)\n\nRust-Yew extension is [available on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlight, renames, hover, and more.\n\nEmmet support should work out of the box, if not please fall back to editing the `settings.json` file:\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> Below configuration works with [LazyVim](https://www.lazyvim.org) configuration and lazy.vim plugin, create a file in `lua/plugins/nvim-lspconfig.lua` (or update your `lspconfig`) with:\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/getting-started/examples.mdx",
    "content": "---\ntitle: 'Examples'\n---\n\nThe Yew repository contains many [examples] (in various states of maintenance).\nWe recommend perusing them to get a feel for how to use different features of the framework.\nWe also welcome Pull Requests and issues for when they inevitably get neglected and need some ♥️\n\nFor more details including a list of examples, refer to the [README].\n\n:::tip\nMost of the examples have a live deployment that can be found at `https://examples.yew.rs/< example_name >`.\nClick the shield on their README page in their respective sub-folder to navigate to the live demo.\n:::\n\n[examples]: https://github.com/yewstack/yew/tree/master/examples\n[readme]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/getting-started/introduction.mdx",
    "content": "---\ntitle: 'Getting Started'\n---\n\nYou will need a couple of tools to compile, build, package and debug your Yew application.\nWhen getting started, we recommend using [Trunk](https://trunkrs.dev/). Trunk is a WASM web application\nbundler for Rust.\n\n## Installing Rust\n\nTo install Rust, follow the [official instructions](https://www.rust-lang.org/tools/install).\n\n:::important\nThe minimum supported Rust version (MSRV) for Yew is `1.76.0`. Older versions will not compile.\nYou can check your toolchain version using\n`rustup show` (under \"active toolchain\") or `rustc --version`. To update your\ntoolchain, run `rustup update`.\n:::\n\n## Install WebAssembly target\n\nRust can compile source codes for different \"targets\" (e.g. different processors). The compilation\ntarget for browser-based WebAssembly is called `wasm32-unknown-unknown`. The following command will\nadd the WebAssembly target to your development environment.\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Install Trunk\n\nTrunk is the recommended tool for managing deployment and packaging and is used throughout the\ndocumentation and examples.\n\n```shell\n# note that this might take a while to install because it compiles everything from scratch\n# Trunk also provides prebuilt binaries for a number of major package managers\n# See https://trunkrs.dev/#install for further details\ncargo install --locked trunk\n```\n\n### Other options\n\nThere are options other than Trunk that may be used for bundling Yew applications. You might want to try one of these options:\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (still in early development)\n\n## Next steps\n\nWith your development environment set up, you can now proceed with reading the documentation.\nIf you like to learn by getting your hands dirty, we recommend you check out our [tutorial](../tutorial).\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew/from-0_18_0-to-0_19_0.mdx",
    "content": "---\ntitle: 'From 0.18.0 to 0.19.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`Yew 0.19.0` has changed a lot, thus this migration will not cover ALL of the changes.\n\nInstead only the most impactful changes are mentioned and the rest should be picked up by `cargo`.\n\n## `html!` requirement for braces around most props\n\nThe syntax of the `html!` macro has been updated, such that in most cases you will need to enclose\nprops with braces.\n\n<Tabs>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,ignore {4}\nlet super_age = 1;\nhtml!{\n    <JapaneseYew\n        age=super_age // ! Will throw an error\n    >\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Valid\" label=\"Valid\">\n\n```rust ,ignore {4}\nlet super_age = 1;\nhtml!{\n    <JapaneseYew\n        age={super_age} // Correct\n    >\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Shorthand\" label=\"Shorthand\">\n\nShorthand initialization has been added:\n\n```rust ,ignore {4}\nlet age = 1;\nhtml!{\n    <JapaneseYew\n        {age}\n    >\n}\n```\n\n  </TabItem>\n</Tabs>\n\nThere is a community provided regex to help automate the update, though we can't promise it will work\nall the time.\n\nIt breaks when it encounters closures (specifically the `|_|` syntax).\n\nfind with `=(?![{\">=\\s])([^\\s></]*(\\s!{0,1}[=|&]{2}\\s[^\\s></]*)*)`\n\nreplace with `={$1}`\n\n## Function components\n\n[Function components](concepts/function-components/introduction.mdx) are a brand new way to write components that\nrequires less boilerplate than their structural counterpart.\n\nWhile this change does not force you to change your codebase, as you migrate from `0.18` to `0.19`, this migration time might present a good opportunity to start using them in your codebase.\n\n## Struct components lifecycle methods and ctx\n\n[Struct components](advanced-topics/struct-components/introduction.mdx) also received changes to their API.\n\n### ShouldRender removed in favor of bool\n\n`ShouldRender` removed in favor of `bool` and can be just find all - replaced throughout your code base.\n\n### ctx, props, link\n\nStruct components no longer own props and link, instead they receive `ctx: &Context<Self>` argument in lifetime methods that can later give you access to `ctx.props() -> &Properties` and `ctx.link() -> &Scope<Self>`.\n\nYou will need to remove `link` and `props` from your component struct fields as such all lifetime methods got updated.\n\n### Lifetime methods in Component trait\n\nFor new API look in the [Component trait](https://github.com/yewstack/yew/blob/9b6bc96826d53ec38aa3ecc02e3a1e132692c411/packages/yew/src/html/component/mod.rs#L37-L97)\n\n## `web-sys` is no longer re-exported\n\nAdd `web-sys` as your project dependency and one by one add the needed features like `Event` or `Window`.\n\n## Services\n\nDuring this update all services were removed in favor of community driven solutions like [gloo](https://github.com/rustwasm/gloo)\n\nRemove this entirely. `yew-services` adds a layer a abstraction which makes it easier to call external resources. This is all well and good but this layer is supposed to be specific to Yew. It would be better if an framework agnostic abstraction existed instead.\n\n- `ConsoleService`\n  Use [gloo-console](https://crates.io/crates/gloo-console) or [`weblog`](https://crates.io/crates/weblog) instead.\n- `DialogService`\n  Use [`gloo-dialogs`](https://docs.rs/gloo-dialogs/) instead.\n- `IntervalService`\n  Use [`gloo-timers`](https://docs.rs/gloo-timers/) instead.\n- `KeyboardService`\n  `on*` event handlers in yew already handle it. Using this service is even more cumbersome because it requires use of `NodeRef` in order to call any functions provided by it.\n\n```rust ,ignore\nlet onkeydown = Callback::from(|e| {\n    e.prevent_default();\n    todo!(\"use `e`, just like in service methods.\");\n});\nhtml! {\n    <input {onkeydown} />\n}\n```\n\n- `ResizeService`\n  Use [`gloo-events`](https://docs.rs/gloo-events) to attach the listener instead.\n- `StorageService`\n  Use [`gloo-storage`](https://docs.rs/gloo-storage/) instead.\n- `TimeoutService`\n  Use [`gloo-timers`](https://docs.rs/gloo-timers/) instead.\n- `WebSocketService`\n  Use [`wasm-sockets`](https://github.com/scratchyone/wasm-sockets) or [`gloo-net`](https://crates.io/crates/gloo-net) instead.\n- `FetchService`\n  Use [`reqwest`](https://crates.io/crates/reqwest) or [`gloo-net`](https://crates.io/crates/gloo-net) instead.\n\n## New crate - yew-agent\n\nYew agents were removed to a separate crate, see [yew agents migration guide](./../yew-agent/from-0_0_0-to-0_1_0)\n\n## Ending note\n\nWe are sorry if some things are not covered in this guide as it was truly a huge update and we hope\nthat the uncovered issues will be clearly explained in error messages emitted by the Rust compiler.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\n## `_as_body` variant of `start_app` is removed\n\nThis method of controlling body has caused issues in event registration and\nSSR hydration. They have been removed. Read more in the [github issue](https://github.com/yewstack/yew/pull/2346).\n\n## New Hooks and Function Components API\n\nThe Function Components and Hooks API are re-implemented with a different mechanism:\n\n- User-defined hooks are now required to have a prefix `use_` and must be marked with the `#[hook]` attribute.\n- Hooks will now report compile errors if they are not called from the top level of a function component\n  or a user defined hook. The limitation existed in the previous version of Yew as well. In this version,\n  It is reported as a compile time error.\n\n## Automatic Message Batching\n\nThe scheduler now schedules its start to the end of the browser event loop.\nAll messages queued during in the meantime will be run in batch.\nThe running order of messages between components are no longer guaranteed, but\nmessages sent to the same component is still acknowledged in an FIFO order.\nIf multiple updates will result in a render, the component will be rendered\nonce.\n\n:::info What this means to developers?\n\nFor struct components, this means that if you send 2 messages to 2 different\ncomponents, they will not be guaranteed to be seen in the same order they are\nsent. If you send 2 messages to the same component, they will still be passed\nto the component in the order they are sent. The messages are not sent to the\ncomponent immediately so you should not assume that when the component receives\na message it still has the same state at the time the message is created.\n\nFor function components, if you store states with `use_state(_eq)`\nand the new value of that state depends on the previous value,\nyou may want to switch to `use_reducer(_eq)`. The new value of the state will\nnot be visible / acknowledged until the next time the component is rendered.\nThe reducer action works similar to messages for struct components and\nwill be sent to the reducer function in the same order as they are dispatched.\nThe reducer function can see all previous changes at the time they are run.\n\n:::\n\n## Yew Renderer\n\n`start_app*` has been replaced by `yew::Renderer`.\n\nYou need to enable feature `csr` to use `yew::Renderer`.\n\n## `ref` prop for Components\n\nComponents no longer have a `ref` prop. Trying to add a node ref to a component\nwill result in a compile error\n\nPreviously node ref passed to a component was bound to the first element rendered by it.\nIf this behavior is still desired, it is recommended to use add a `r#ref` field to the\ncomponent's properties and bind it manually\n\n## `changed` Method on Components\n\nThe method `fn changed()` has now a new argument to provide the old properties\nto the function.\n\nThe old method's signature was:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>) -> bool\n```\n\nThe new method's signature is now:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool\n```\n\nThis can be adjusted automatically in your code using this bash script (save\nyour code before running this!):\n\n```bash\nperl -p -i -e  's/fn changed\\(&mut self, (\\w+): &Context<Self>\\)/fn changed(&mut self, $1: &Context<Self>, _old_props: &Self::Properties)/g' $(find . -name \\*.rs)\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew/from-0_20_0-to-0_21_0.mdx",
    "content": "---\ntitle: 'From 0.20.0 to 0.21.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Dependencies as first hook argument and `use_effect_with`\n\n- Replace `use_effect_with_deps` with new `use_effect_with`\n- `use_effect_with`, `use_callback`, `use_memo` now take dependencies as their first argument\n\n### Automated refactor\n\nWith the help of [https://ast-grep.github.io](https://ast-grep.github.io/guide/quick-start.html)\nHere are commands that can do the refactoring for you.\n\n```bash\nsg --pattern 'use_effect_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_effect_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_callback($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_callback($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_callback($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_callback($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_memo($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_memo($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n```\n\n### Reasoning\n\nThis will enable more ergonomic use of hooks, consider:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\n{\n    let id = some_dep.id(); // Have to extract it in advance, some_dep is moved already in the second argument\n    use_effect_with_dep(move |_| { todo!(); drop(some_dep); }, id);\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\nuse_effect_with(some_dep.id(), move |_| { todo!(); drop(some_dep); });\n\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew/from-0_20_0-to-next.mdx",
    "content": "---\ntitle: 'From 0.19.0 to Next'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Dependencies as first hook argument and `use_effect_with`\n\n- Replace `use_effect_with_deps` with new `use_effect_with`\n- `use_effect_with`, `use_callback`, `use_memo` now take dependencies as their first argument\n\n### Automated refactor\n\nWith the help of [https://ast-grep.github.io](https://ast-grep.github.io/guide/quick-start.html)\nHere are commands that can do the refactoring for you.\n\n```bash\nsg --pattern 'use_effect_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_effect_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_callback($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_callback($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_callback($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_callback($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_memo($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_memo($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n```\n\n### Reasoning\n\nThis will enable more ergonomic use of hooks, consider:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\n{\n    let id = some_dep.id(); // Have to extract it in advance, some_dep is moved already in the second argument\n    use_effect_with_dep(move |_| { todo!(); drop(some_dep); }, id);\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\nuse_effect_with(some_dep.id(), move |_| { todo!(); drop(some_dep); });\n\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew-agent/from-0_0_0-to-0_1_0.mdx",
    "content": "---\ntitle: 'From 0.0.0 to 0.1.0'\n---\n\nThis is the first release of `yew-agents` being separated from `yew`\n\nThe only thing you will need to do is change the import paths from `yew::*` to `yew_agents::*`\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew-agent/from-0_1_0-to-0_2_0.mdx",
    "content": "---\ntitle: 'From 0.1.0 to 0.2.0'\n---\n\n## Removal of `Context` and `Job` Agents\n\nThe `Context` and `Job` Agents have been removed in favour of Yew's Context API.\n\nYou can see the updated [`pub_sub`](https://github.com/yewstack/yew/tree/master/examples/pub_sub)\nwhich demonstrate how to use the context API.\n\nFor users of `yew_agent::utils::store`, you may switch to third party solutions like: [Yewdux](https://github.com/intendednull/yewdux) or [Bounce](https://github.com/futursolo/bounce).\n\n## `Threaded` has been separated into `PublicAgent` and `PrivateAgent`\n\nReplace `use yew_agent::Threaded;` with `use yew_agent::PublicAgent;`.\n\n:::note\n\n`Threaded` was never implemented for Private Agents.\nAll existing web worker-based agents are Public Agents.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew-router/from-0_15_0-to-0_16_0.mdx",
    "content": "---\ntitle: 'From 0.15.0 to 0.16.0'\n---\n\nThe router API has been completely rewritten in `0.16.0`.\n\nBecause it is such a radical change, there are too many things to list out here, so we highly\nrecommend to read the updated [router documentation](./../../concepts/router) and adapt your app\naccordingly.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/migration-guides/yew-router/from-0_16_0-to-0_17_0.mdx",
    "content": "---\ntitle: 'From 0.16.0 to 0.17.0'\n---\n\n## `Switch::render` is no longer needed\n\nThe `<Switch />` component now accepts a closure of `Fn(Routable) -> Html` as\nthe render function directly.\n\n## `navigator` API\n\nThe History API has been replaced with the Navigator API.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nA proposal for integrated CSS support can be found here:\n[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\nThis contains a lot of discussion about how to best integrate CSS support into Yew.\n\nCurrently, the approach we have adopted is to encourage developers to build many systems, before\nadopting the most popular one.\n\nThe community is currently developing several projects to make it easy to add styles to\nprojects. A few are given below:\n\n#### Component Libraries\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - A styling framework for Yew without any JavaScript dependencies.\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design Components.\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS Components.\n- [Yewtify](https://github.com/yewstack/yewtify) – Implements the features provided by the Vuetify framework in Yew.\n\n#### Styling Solutions\n\n- [stylist](https://github.com/futursolo/stylist-rs) - A CSS-in-Rust styling solution for WebAssembly Applications.\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind Utility Classes.\n\n:::important contribute\nIf you're developing a project adding styles to Yew please submit a PR adding yourself to this list!\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/more/debugging.mdx",
    "content": "---\ntitle: 'Debugging'\n---\n\n## Panics\n\nYew automatically logs panics in the browser console.\n\n## Console Logging\n\nIn JavaScript, `console.log()` is used to log to the browser console. Some options for Yew are listed below.\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate integrates with [`log`](https://crates.io/crates/log) crate to send the log level, source line, and filename to the browser console.\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nThis crate is part of Gloo, a collection of libraries providing ergonomic Rust wrappers for browser APIs.\nThe `log!` macro can take a `JsValue` directly which is slightly easier to use than `wasm_logger`.\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` can be used with [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) to output messages to the browser console.\n\n```rust, ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## Debugging component lifecycles\n\n[`tracing`](https://crates.io/crates/tracing) can be used to collect event information related to a component's lifecycle. `tracing` also comes with a feature flag for `log` support, which integrates nicely with `wasm-logger`.\n\n[Compile time filters](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) can be used to adjust verbosity or disable logging, which should result in a smaller Wasm file.\n\n## Source Maps\n\nThere is [some support](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) for source maps.\nHowever, some configuration is required.\n\n## Past Articles\n\nSome past articles on the state of debugging in WebAssembly in Rust can be found below. They may serve as interesting reads.\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) does not support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/more/deployment.mdx",
    "content": "---\ntitle: 'Deployment'\ndescription: 'Deploying Yew applications'\n---\n\nWhen you are ready to deploy your Yew application to a server, you have various options for deployment.\n\n`trunk build --release` builds your app in release mode. Set up your HTTP server so that it serves `index.html` whenever your site is visited, and requests to static paths like `index_<hash>.js` and `index_bg_<hash>.wasm` are served with the contents of their respective contents from the dist directory generated by trunk.\n\n:::important A note about `trunk serve --release`\nDo **not** use `trunk serve --release` to serve your application in production.\nIt should only be used for testing the release build during development\n:::\n\n## Server configuration\n\n### Serving `index.html` as a fallback\n\nIf the application uses the [Yew router](concepts/router.mdx), you must configure the server to return the `index.html` when asked for a file that it does not have.\n\nAn application with Yew router is built as a [Single Page Application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA). When the user navigates to a URL from within a running client, the router interprets the URL and routes to that page.\n\nBut on a fresh load, such as when navigating to the page by entering it in the address bar or refreshing the page, all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router. A wrongly configured server would return with the status 404 - Not Found.\n\nBy returning `index.html` instead, the app loads as it normally would, as if the request was for `/` until the router notices that the route is `/show/42` and displays the appropriate contents.\n\n### Configuring correct MIME-type for Web Assembly asset.\n\nThe WASM files must be served with the [Content-Type header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) set to `application/wasm` MIME-type.\n\nMost servers and hosting services already do this by default. If yours does not, consult its documentation. An incorrect MIME type will, in most web browsers, result in an error similar to the following:\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## Building for Relative Paths\n\nBy default, trunk will assume that your site is being served at `/` and build the site accordingly. This behavior can be overridden by adding `<base data-trunk-public-url />` to the `index.html` file. Trunk rewrites this tag to contain the value passed to `--public-url`. Yew router automatically detects the presence of `<base />` and handles it appropriately.\n\n## Customizing behavior using environment variables\n\nIt is common to customize the build environment by using environment variables. Since the app is run in a browser, we cannot read the environment variables at runtime.\nThe [`std::env!`](https://doc.rust-lang.org/std/macro.env.html) macro can be used to obtain a value of an environment variable at compile time.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/more/roadmap.mdx",
    "content": "---\ntitle: 'Roadmap'\ndescription: 'The planned feature roadmap for the Yew framework'\n---\n\n## Prioritization\n\nThe prioritization of upcoming features and focuses of the framework is determined by the community.\nIn Spring 2020, a developer survey was sent out to collect feedback on the direction of the project.\nYou can find the summary in the [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D).\n\n:::note\nStatus of all major initiatives can be tracked on the Yew Github [project board](https://github.com/yewstack/yew/projects)\n:::\n\n## Focuses\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Most requested features\n\n1. [Functional Components](https://github.com/yewstack/yew/projects/3)\n2. [Component Library](https://github.com/yewstack/yew/projects/4)\n3. Better state management\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n### Issues needed for production readiness\n\n- Improve Yew test coverage\n- Reduce binary size\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- Create tutorial\n- Simplify project setup\n\n### Pain points\n\n- [Component boilerplate](https://github.com/yewstack/yew/issues/830)\n- [Agents](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/more/testing.mdx",
    "content": "---\ntitle: 'Testing apps'\ndescription: 'Testing your app'\n---\n\n:::info\nWe are working on making it easy to test components, but this is currently a work in progress.\n\nSupport for [shallow rendering](https://github.com/yewstack/yew/issues/1413) can be found in the GitHub repository.\n:::\n\n## Snapshot testing\n\nYew exposes the `yew::tests::layout_tests` module to facilitate snapshot testing of components.\n\n:::important contribute\nHelp improve the documentation for snapshot testing.\n:::\n\n## wasm_bindgen_test\n\nThe Rust/WASM working group maintains a crate called [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nwhich allows you to run tests in a browser in a similar fashion to how the built-in `#[test]` procedural macro works.\nMore information is given in the [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nfor this module.\n"
  },
  {
    "path": "website/versioned_docs/version-0.21/tutorial/index.mdx",
    "content": "---\ntitle: 'Tutorial'\nslug: /tutorial\n---\n\n## Introduction\n\nIn this hands-on tutorial, we will take a look at how we can use Yew to build web applications.\n**Yew** is a modern [Rust](https://www.rust-lang.org/) framework for building front-end web apps using [WebAssembly](https://webassembly.org/).\nYew encourages a reusable, maintainable, and well-structured architecture by leveraging Rust's powerful type system.\nA large ecosystem of community-created libraries, known in Rust as [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html),\nprovide components for commonly-used patterns such as state management.\n[Cargo](https://doc.rust-lang.org/cargo/), the package manager for Rust, allows us to take advantage of the\nnumerous crates available on [crates.io](https://crates.io), such as Yew.\n\n### What we are going to build\n\nRustconf is an intergalactic gathering of the Rust community that happens annually.\nRustconf 2020 had a plethora of talks that provided a good amount of information.\nIn this hands-on tutorial, we will be building a web application to help fellow Rustaceans\nget an overview of the talks and watch them all from one page.\n\n## Setting up\n\n### Prerequisites\n\nThis tutorial assumes you are already familiar with Rust. If you are new to Rust,\nthe free [Rust Book](https://doc.rust-lang.org/book/ch00-00-introduction.html) offers a great starting point for\nbeginners and continues to be an excellent resource even for experienced Rust developers.\n\nEnsure the latest version of Rust is installed by running `rustup update` or by\n[installing rust](https://www.rust-lang.org/tools/install) if you have not already done so.\n\nAfter installing Rust, you can use Cargo to install `trunk` by running:\n\n```bash\ncargo install trunk\n```\n\nWe will also need to add the WASM build target by running:\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### Setting up the project\n\nFirst, create a new cargo project:\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nTo verify the Rust environment is set up properly, run the initial project using the cargo build tool.\nAfter the output about the build process, you should see the expected \"Hello, world!\" message.\n\n```bash\ncargo run\n```\n\n## Our first static page\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\nUpdate the files as follows:\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.21\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[function_component(App)]\nfn app() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nNow, let's create an `index.html` at the root of the project.\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### Start the development server\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve --open\n```\n\n:::info\nRemove option '--open' to not open your default browser `trunk serve`.\n:::\n\nTrunk will open your application in your default browser, watch the project directory and helpfully rebuild your\napplication if you modify any source files.\nThis will fail if the socket is being used by another application.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\nIf you are curious, you can run `trunk help` and `trunk help <subcommand>` for more details on what is happening.\n\n### Congratulations\n\nYou have now successfully set up your Yew development environment and built your first Yew web application.\n\n## Building HTML\n\nYew makes use of Rust's procedural macros and provides us with a syntax similar to JSX (an extension to JavaScript\nwhich allows you to write HTML-like code inside JavaScript) to create the markup.\n\n### Converting classic HTML\n\nSince we already have a pretty good idea of what our website will look like, we can simply translate our mental draft\ninto a representation compatible with `html!`. If you are comfortable writing simple HTML, you should have no problem\nwriting marking inside `html!`. It is important to note that the macro does differ from HTML in a few ways:\n\n1. Expressions must be wrapped in curly braces (`{ }`)\n2. There must only be one root node. If you want to have multiple elements without wrapping them in a container,\n   an empty tag/fragment (`<> ... </>`) is used\n3. Elements must be closed properly.\n\nWe want to build a layout that looks something like this in raw HTML:\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nNow, let's convert this HTML into `html!`. Type (or copy/paste) the following snippet into the body of `app` function\nsuch that the value of `html!` is returned by the function\n\n```rust ,ignore\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{\"Videos to watch\"}</h3>\n            <p>{ \"John Doe: Building and breaking things\" }</p>\n            <p>{ \"Jane Smith: The development process\" }</p>\n            <p>{ \"Matt Miller: The Web 7.0\" }</p>\n            <p>{ \"Tom Jerry: Mouseless development\" }</p>\n        </div>\n        <div>\n            <h3>{ \"John Doe: Building and breaking things\" }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    </>\n}\n```\n\nRefresh the browser page, and you should see the following output displayed:\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### Using Rust language constructs in the markup\n\nA big advantage of writing markup in Rust is that we get all the coolness of Rust in our markup.\nNow, instead of hardcoding the list of videos in the HTML, let's define them as a `Vec` of `Video` structs.\nWe create a simple `struct` (in `main.rs` or any file of our choice) that will hold our data.\n\n```rust\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\nNext, we will create instances of this struct in our `app` function and use those instead of hardcoding the data:\n\n```rust\nuse website_test::tutorial::Video; // replace with your own path\n\nlet videos = vec![\n    Video {\n        id: 1,\n        title: \"Building and breaking things\".to_string(),\n        speaker: \"John Doe\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 2,\n        title: \"The development process\".to_string(),\n        speaker: \"Jane Smith\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 3,\n        title: \"The Web 7.0\".to_string(),\n        speaker: \"Matt Miller\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n    Video {\n        id: 4,\n        title: \"Mouseless development\".to_string(),\n        speaker: \"Tom Jerry\".to_string(),\n        url: \"https://youtu.be/PsaFVLr8t4E\".to_string(),\n    },\n];\n```\n\nTo display them, we need to convert the `Vec` into `Html`. We can do that by creating an iterator,\nmapping it to `html!` and collecting it as `Html`:\n\n```rust ,ignore\nlet videos = videos.iter().map(|video| html! {\n    <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n}).collect::<Html>();\n```\n\n:::tip\nKeys on list items help Yew keep track of which items have changed in the list, resulting in faster re-renders. [It is always recommended to use keys in lists](/concepts/html/lists.mdx#keyed-lists).\n:::\n\nAnd finally, we need to replace the hardcoded list of videos with the `Html` we created from the data:\n\n```rust ,ignore {6-10}\nhtml! {\n    <>\n        <h1>{ \"RustConf Explorer\" }</h1>\n        <div>\n            <h3>{ \"Videos to watch\" }</h3>\n-           <p>{ \"John Doe: Building and breaking things\" }</p>\n-           <p>{ \"Jane Smith: The development process\" }</p>\n-           <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-           <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           { videos }\n        </div>\n        // ...\n    </>\n}\n```\n\n## Components\n\nComponents are the building blocks of Yew applications. By combining components, which can be made of other components,\nwe build our application. By structuring our components for re-usability and keeping them generic, we will be able to use\nthem in multiple parts of our application without having to duplicate code or logic.\n\nThe `app` function we have been using so far is a component, called `App`. It is a \"function component\".\nThere are two different types of components in Yew.\n\n1. Struct Components\n2. Function Components\n\nIn this tutorial, we will be using function components.\n\nNow, let's split up our `App` component into smaller components. We begin by extracting the videos list into\nits own component.\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[function_component(VideosList)]\nfn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n    videos.iter().map(|video| html! {\n        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n    }).collect()\n}\n```\n\nNotice the parameters of our `VideosList` function component. A function component takes only one argument which\ndefines its \"props\" (short for \"properties\"). Props are used to pass data down from a parent component to a child component.\nIn this case, `VideosListProps` is a struct that defines the props.\n\n:::important\nThe struct used for props must implement `Properties` by deriving it.\n:::\n\nFor the above code to compile, we need to modify the `Video` struct like this:\n\n```rust {1}\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\nNow, we can update our `App` component to make use of `VideosList` component.\n\n```rust ,ignore {4-7,13-14}\n#[function_component(App)]\nfn app() -> Html {\n    // ...\n-    let videos = videos.iter().map(|video| html! {\n-        <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-    }).collect::<Html>();\n-\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               { videos }\n+               <VideosList videos={videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nBy looking at the browser window, we can verify that the lists are rendered as they should be.\nWe have moved the rendering logic of lists to its component. This shortens the `App` component’s source code,\nmaking it easier for us to read and understand.\n\n### Making it interactive\n\nThe final goal here is to display the selected video. To do that, `VideosList` component needs to \"notify\" its\nparent when a video is selected, which is done via a `Callback`. This concept is called \"passing handlers\".\nWe modify its props to take an `on_click` callback:\n\n```rust ,ignore {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+    on_click: Callback<Video>\n}\n```\n\nThen we modify the `VideosList` component to \"emit\" the selected video to the callback.\n\n```rust ,ignore {2-4,6-12,15-16}\n#[function_component(VideosList)]\n-fn videos_list(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn videos_list(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+    let on_click = on_click.clone();\n    videos.iter().map(|video| {\n+        let on_video_select = {\n+            let on_click = on_click.clone();\n+            let video = video.clone();\n+            Callback::from(move |_| {\n+                on_click.emit(video.clone())\n+            })\n+        };\n\n        html! {\n-            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+            <p key={video.id} onclick={on_video_select}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }).collect()\n}\n```\n\nNext, we need to modify the usage of `VideosList` to pass that callback. But before doing that, we should create\na new component, `VideoDetails`, that is displayed when a video is clicked.\n\n```rust\nuse website_test::tutorial::Video;\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[function_component(VideoDetails)]\nfn video_details(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ video.title.clone() }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\nNow, modify the `App` component to display `VideoDetails` component whenever a video is selected.\n\n```rust ,ignore {4,6-11,13-15,22-23,25-29}\n#[function_component(App)]\nfn app() -> Html {\n    // ...\n+    let selected_video = use_state(|| None);\n\n+    let on_video_select = {\n+        let selected_video = selected_video.clone();\n+        Callback::from(move |video: Video| {\n+            selected_video.set(Some(video))\n+        })\n+    };\n\n+    let details = selected_video.as_ref().map(|video| html! {\n+        <VideoDetails video={video.clone()} />\n+    });\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-               <VideosList videos={videos} />\n+               <VideosList videos={videos} on_click={on_video_select.clone()} />\n            </div>\n+            { for details }\n-            <div>\n-                <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-                <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-            </div>\n        </>\n    }\n}\n```\n\nDo not worry about the `use_state` right now, we will come back to that later.\nNote the trick we pulled with `{ for details }`. `Option<_>` implements `Iterator` so we can use it to display the only\nelement returned by the `Iterator` with a special `{ for ... }` syntax\n[supported by the `html!` macro](concepts/html/lists).\n\n### Handling state\n\nRemember the `use_state` used earlier? That is a special function, called a \"hook\". Hooks are used to \"hook\" into\nthe lifecycle of a function component and perform actions. You can learn more about this hook, and others\n[here](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks).\n\n:::note\nStruct components act differently. See [the documentation](advanced-topics/struct-components/introduction.mdx) to learn about those.\n:::\n\n## Fetching data (using external REST API)\n\nIn a real-world application, data will usually come from an API instead of being hardcoded. Let's fetch our\nvideos list from an external source. For this we will need to add the following crates:\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  For making the fetch call.\n- [`serde`](https://serde.rs) with derive features\n  For de-serializing the JSON response\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  For executing Rust Future as a Promise\n\nLet's update the dependencies in `Cargo.toml` file:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-net = \"0.2\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nwasm-bindgen-futures = \"0.4\"\n```\n\n:::note\nWhen choosing dependencies make sure they are `wasm32` compatible!\nOtherwise you won't be able to run your application.\n:::\n\nUpdate the `Video` struct to derive the `Deserialize` trait:\n\n```rust ,ignore {1, 3-4}\n+ use serde::Deserialize;\n\n- #[derive(Clone, PartialEq)]\n+ #[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: String,\n    speaker: String,\n    url: String,\n}\n```\n\nNow as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data\n\n```rust ,ignore {1,5-25,34-35}\n+ use gloo_net::http::Request;\n\n#[function_component(App)]\nfn app() -> Html {\n-    let videos = vec![\n-        // ...\n-    ]\n+    let videos = use_state(|| vec![]);\n+    {\n+        let videos = videos.clone();\n+        use_effect_with((), move |_| {\n+            let videos = videos.clone();\n+            wasm_bindgen_futures::spawn_local(async move {\n+                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                    .send()\n+                    .await\n+                    .unwrap()\n+                    .json()\n+                    .await\n+                    .unwrap();\n+                videos.set(fetched_videos);\n+            });\n+            || ()\n+        });\n+    }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{\"Videos to watch\"}</h3>\n-                <VideosList videos={videos} on_click={on_video_select.clone()} />\n+                <VideosList videos={(*videos).clone()} on_click={on_video_select.clone()} />\n            </div>\n            { for details }\n        </>\n    }\n}\n```\n\n:::note\nWe are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have\n[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).\n:::\n\nNow, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.\nTo fix that, we need a proxy server. Luckily trunk provides that.\n\nUpdate the following line:\n\n```rust ,ignore {2-3}\n// ...\n-                let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n// ...\n```\n\nNow, rerun the server with the following command:\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nRefresh the tab and everything should work as expected.\n\n## Wrapping up\n\nCongratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.\n\n## What's next\n\nThis application is very far from perfect or useful. After going through this tutorial,\nyou can use it as a jumping-off point to explore more advanced topics.\n\n### Styles\n\nOur apps look very ugly. There is no CSS or any kind of style.\nUnfortunately, Yew does not offer a built-in way to style components. See [Trunk's assets](https://trunkrs.dev/assets/)\nto learn how to add style sheets.\n\n### More libraries\n\nOur app made use of only a few external dependencies. There are lots of crates out there that can be used.\nSee [external libraries](/community/external-libs) for more details.\n\n### Learning more about Yew\n\nRead our [official documentation](../getting-started/introduction.mdx). It explains a lot of concepts in much more detail.\nTo learn more about the Yew API, see our [API docs](https://docs.rs/yew).\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! {{for modified_children}}\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: 'Low level details about the framework'\n---\n\n# Low-level library internals\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: 'Optimizations & Best Practices'\nsidebar_label: Optimizations\ndescription: 'Make your app faster'\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nTo avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications, it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component or just a big\nfunction that produces `Html`. Code that is shared between the crates containing different parts of\nthe application could be stored in a separate crate which the project depends on.\nIn the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and additionally render the component you are working on.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther, it is possible to optimize the size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## Rendering `<head>` Tags\n\nA common need with SSR is rendering dynamic `<head>` content (e.g. `<title>`,\n`<meta>`) so that crawlers and social previews see the right metadata on first\nload.\n\n`ServerRenderer` only renders your component tree (typically at the body of the document),\nit has no access to `<head>`. Head tags must therefore be generated **on the server, outside of\nYew**, and spliced into the HTML template before it is sent to the client.\n\nThe [`ssr_router` example](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) demonstrates this pattern: the server recognizes the\nroute from the request URL, generates the appropriate `<title>` and `<meta>`\ntags, and injects them into the Trunk-generated `index.html` before\n`</head>`.\n\n:::info\n\nFor a fully SSR-compatible third-party solution, use [the `<Helmet/>` component from Bounce](https://docs.rs/bounce/latest/bounce/helmet/index.html).\n\n:::\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## Single thread mode\n\nYew supports single thread mode for server-side rendering by `yew::LocalServerRenderer`. This mode would work in a single thread environment like WASI.\n\n```rust\n// Build using `wasm32-wasip1` target or `wasm32-wasip2` target.\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\nExample: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\nIf you are using the `wasm32-unknown-unknown` target to build a SSR application, you can use the `not_browser_env` feature flag to disable access of browser-specific APIs inside of Yew. This would be useful on serverless platforms like Cloudflare Worker.\n:::\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'Lifecycle'\ndescription: 'Components and their lifecycle hooks'\n---\n\nThe `Component` trait has a number of methods which need to be implemented; Yew will call these at different\nstages in the lifecycle of a component.\n\n## Lifecycle\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## Lifecycle Methods\n\n### Create\n\nWhen a component is created, it receives properties from its parent component and is stored within\nthe `Context<Self>` that is passed down to the `create` method. The properties can be used to\ninitialize the component's state and the \"link\" can be used to register callbacks or send messages to the component.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nThe `view` method allows you to describe how a component should be rendered to the DOM. Writing\nHTML-like code using Rust functions can become quite messy, so Yew provides a macro called `html!`\nfor declaring HTML and SVG nodes (as well as attaching attributes and event listeners to them) and a\nconvenient way to render child components. The macro is somewhat similar to React's JSX (the\ndifferences in programming language aside).\nOne difference is that Yew provides a shorthand syntax for properties, similar to Svelte, where instead of writing `onclick={onclick}`, you can just write `{onclick}`.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\nFor usage details, check out [the `html!` guide](concepts/html/introduction.mdx).\n\n### Rendered\n\nThe `rendered` component lifecycle method is called once `view` has been called and Yew has rendered\nthe results to the DOM, but before the browser refreshes the page. This method is useful when you\nwant to perform actions that can only be completed after the component has rendered elements. There\nis also a parameter called `first_render` which can be used to determine whether this function is\nbeing called on the first render, or instead a subsequent one.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nNote that this lifecycle method does not require implementation and will do nothing by default.\n:::\n\n### Update\n\nCommunication with components happens primarily through messages which are handled by the\n`update` lifecycle method. This allows the component to update itself\nbased on what the message was, and determine if it needs to re-render itself. Messages can be sent\nby event listeners, child components, Agents, Services, or Futures.\n\nHere is an example of what an implementation of `update` could look like:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nComponents may be re-rendered by their parents. When this happens, they could receive new properties\nand need to re-render. This design facilitates parent-to-child component communication by just\nchanging the values of a property. There is a default implementation that re-renders the component\nwhen props are changed.\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods but are only caused when trying to update\nthe same component after every render, when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it is often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample, you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to the component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nProperties enable child and parent components to communicate with each other.\nEvery component has an associated properties type which describes what is passed down from the parent.\nIn theory, this can be any type that implements the `Properties` trait, but in practice, there is no\nreason for it to be anything but a struct where each field represents a property.\n\n## Derive macro\n\nInstead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to\nautomatically generate the implementation instead.\nTypes for which you derive `Properties` must also implement `PartialEq`.\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they are set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: 'Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` keyword can be used inside of any HTML element or component to get the DOM `Element` that\nthe item is attached to. This can be used to make changes to the DOM outside of the `view` lifecycle\nmethod.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\nThe syntax is:\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/agents.mdx",
    "content": "---\ntitle: 'Agents'\ndescription: \"Yew's Actor System\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nAgents are a way to offload tasks to web workers.\n\nIn order for agents to run concurrently, Yew uses\n[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).\n\n## Lifecycle\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## Types of Agents\n\n### Reaches\n\n- Public - There will exist at most one instance of a Public Agent at any given time. Bridges will\n  spawn or connect to an already spawned agent in a web worker.\n  When no bridges are connected to this agent, the agent will disappear.\n\n- Private - Spawn a new agent in a web worker for every new bridge. This is good for moving shared but\n  independent behavior that communicates with the browser out of components. When\n  the connected bridge is dropped, the agent will disappear.\n\n- Global \\(WIP\\)\n\n## Communication between Agents and Components\n\n### Bridges\n\nA bridge allows bi-directional communication between an agent and a component. Bridges also allow agents to communicate with one another.\n\nA `use_bridge` hook is also provided to create bridges in a function component.\n\n### Dispatchers\n\nA dispatcher allows uni-directional communication between a component and an agent. A dispatcher allows a component to send messages to an agent.\n\n## Overhead\n\nAgents use web workers \\(i.e. Private and Public\\). They incur a serialization overhead on the\nmessages they send and receive. Agents use [bincode](https://github.com/bincode-org/bincode) to communicate\nwith other threads, so the cost is substantially higher than just calling a function.\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) example shows how\n  components can send messages to and receive messages from agents.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'CSS with classes!'\ndescription: 'A handy macro to handle classes'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew does not natively provide a CSS-in-Rust solution but helps with styling by providing\nprogrammatic ways to interact with the HTML `class` attribute.\n\n## `classes!` macro\n\nThe `classes!` macro and associated `Classes` struct simplify the use of HTML classes:\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\nWe will expand upon this concept in [more CSS](../../more/css).\n\n## Inline Styles\n\nCurrently Yew does not provide any special help with inline styles specified via the `style` attribute,\nbut you can use it like any other HTML attribute:\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\nWe will expand upon this concept in [more CSS](../../more/css).\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'HTML with html!'\ndescription: 'It is HTML but not quite!'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYou can write expressions resembling HTML with the `html!` macro. Behind the scenes, Yew turns\nit into rust code representing the DOM to generate.\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nSimilar to format expressions, there is an easy way to embed values from the surrounding\ncontext into the HTML by applying curly brackets:\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\nOne major rule comes with the use of `html!` - you can only return 1 wrapping node.\nTo render a list of multiple elements, `html!` allows fragments. Fragments are tags\nwithout a name, that produce no HTML element by themselves.\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// error: only one root HTML element allowed\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// fixed: using HTML fragments\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\nWe will introduce Yew and HTML further in depth in [more HTML](concepts/html/introduction.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JS with RS'\ndescription: 'JavaScript with Rust'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files, while also keeping the underlying technology\n> accessible where necessary.\n\nAs of today, WebAssembly is not feature-complete for DOM interactions. This means even in Yew we\nsometimes rely on calling JavaScript. What follows is an overview of the involved libraries.\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool that bridges calls between JavaScript and Rust functions.\n\nWe highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./wasm-bindgen.mdx).\n\n## web-sys\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs and allows us to write JavaScript code in a rustyfied and safe way.\n\nExample:\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\nOnce again we highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./web-sys.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool to facilitate\nhigh-level interactions between Wasm modules and JavaScript; it is built with Rust by\n[The Rust and WebAssembly Working Group](https://rustwasm.github.io/).\n\nYew uses `wasm-bindgen` to interact with the browser through a number of crates:\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nThis section will explore some of these crates at a high level, to make it easier to understand\nand use `wasm-bindgen` APIs with Yew. For a more in-depth guide to `wasm-bindgen` and its associated\ncrates then check out [The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/).\n\nFor documentation on the above crates check out [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html).\n\n:::tip\nUse the `wasm-bindgen` doc.rs search to find browser APIs and JavaScript types that have been imported\nover using `wasm-bindgen`.\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nThis crate provides many of the building blocks for the rest of the crates above. In this section we\nare only going to cover two main areas of the `wasm-bindgen` crate and that is the macro and some\ntypes/traits you will see pop up again and again.\n\n### `#[wasm_bindgen]` macro\n\nThe `#[wasm_bindgen]` macro provides an interface between Rust and JavaScript, providing a system\nfor translating between the two. Using this macro is more advanced, and you should not need to reach\nfor it unless you are trying to use an external JavaScript library. The `js-sys` and `web-sys`\ncrates expose `wasm-bindgen` definitions for built-in JavaScript types and browser APIs.\n\nLet's go over a simple example of using the `#[wasm-bindgen]` macro to import some specific flavours\nof the [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) function.\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// First up let's take a look of binding `console.log` manually, without the\n// help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations\n// manually ourselves, and the correctness of our program relies on the\n// correctness of these annotations!\n#[wasm_bindgen]\nextern \"C\" {\n    // Use `js_namespace` here to bind `console.log(..)` instead of just\n    // `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // The `console.log` is quite polymorphic, so we can bind it with multiple\n    // signatures. Note that we need to use `js_name` to ensure we always call\n    // `log` in JS.\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // Multiple arguments too!\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// using the imported functions!\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_This example was adapted from [1.2 Using console.log of The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html)_.\n\n### Simulating inheritance\n\nInheritance between JavaScript classes is a core feature of the Javascript language and the DOM\n(Document Object Model) is designed around it. When types are imported using `wasm-bindgen` you can\nalso add attributes that describe their inheritance.\n\nIn Rust, this inheritance is represented using the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\nand [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) traits. An example of this\nmight help; so say you have three types `A`, `B`, and `C` where `C` extends `B` which in turn\nextends `A`.\n\nWhen importing these types the `#[wasm-bindgen]` macro will implement the `Deref` and `AsRef`\ntraits in the following way:\n\n- `C` can `Deref` to `B`\n- `B` can `Deref` to `A`\n- `C` can be `AsRef` to `B`\n- Both `C` & `B` can be `AsRef` to `A`\n\nThese implementations allow you to call a method from `A` on an instance of `C` and to use `C` as if\nit was `&B` or `&A`.\n\nIt is important to note that every single type imported using `#[wasm-bindgen]` has the same root type,\nyou can think of it as the `A` in the example above, this type is [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) which has\nits section below.\n\n_[extends section in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\nThis is a representation of an object owned by JavaScript, this is a root catch-all type for `wasm-bindgen`.\nBecause JavaScript does not have a strong type system, any type that comes from `wasm-bindgen` is a `JsValue`.\nFunctions in JavaScript do not define the type of any variables they take in or return; variables can be\nany valid JavaScript value, hence `JsValue`. If you are working with imported functions or types that\naccept a `JsValue`, then any imported value is _technically_ valid.\n\nEven though `JsValue` may be accepted by a JS function, that function may still only _actually_ accept certain types.\nPassing an incorrect `JsValue` can lead to an exception which triggers a panic - so when using raw `wasm-bindgen` APIs,\ncheck the your JavaScript's documentation for types of inputs that will cause an exception (and a panic).\n\n_[`JsValue` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)._\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust has a strong type system and JavaScript...doesn't 😞. For Rust to maintain these\nstrong types but still be convenient, the WebAssembly group came up with a pretty neat trait `JsCast`.\nIts job is to help you move from one JavaScript \"type\" to another, which sounds vague, but it means\nthat if you have one type which you know is another, then you can use the functions of `JsCast`\nto jump from one type to the other. It is a nice trait to get to know when working with `web-sys`,\n`wasm_bindgen`, `js-sys` - you will notice lots of types will implement `JsCast` from those crates.\n\n`JsCast` provides both checked and unchecked methods of casting - so if at runtime if you are\nunsure what type a certain object is, you can try to cast it, which returns possible failure types like\n[`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) and\n[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).\n\nA common example of this in [`web-sys`](./web-sys.mdx) is when you are trying to get the\ntarget of an event. You might know what the target element is, but the\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API will always return an [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target).\nYou will need to cast it to the element type so you can call its methods.\n\n```rust\n// need to import the trait.\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // maybe the target is a select element?\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // do something amazing here\n        return;\n    }\n\n    // if it wasn't a select element then I KNOW it's a input element!\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\nThe [`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref)\nmethod is a checked cast that returns an `Option<&T>`, which means the original type\ncan be used again if the cast failed and thus returned `None`. The\n[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nmethod will consume `self`, as per convention for `into` methods in Rust, and the type returned is\n`Result<T, Self>`. If the casting fails, the original `Self` value is returned in `Err`. You can try again\nor do something else with the original type.\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\nThe `Closure` type provides a way to transfer Rust closures to JavaScript. The closures passed to\nJavaScript must have a `'static` lifetime for soundness reasons.\n\nThis type is a \"handle\" in the sense that whenever it is dropped, it will invalidate the JS\nclosure that it refers to. Any usage of the closure in JS after the Closure has been dropped will\nraise an exception.\n\n`Closure` is often used when you are working with a `js-sys` or `web-sys` API that accepts a type\n[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html).\nAn example of using a `Closure` in Yew can be found in the [Using `Closure` section](../html/events.mdx#using-closure-verbose)\non the [Events](../html/events.mdx) page.\n\n_[`Closure` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\nThe `js-sys` crate provides bindings/imports of JavaScript's standard, built-in objects, including\ntheir methods and properties.\n\nThis does not include any web APIs; that's what [`web-sys`](./web-sys.mdx) is for!\n\n_[`js-sys` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\nThe `wasm-bindgen-futures` crate provides a bridge for working with JavaScript Promise types as a\nRust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html), and contains\nutilities to turn a rust Future into a JavaScript Promise. This can be useful when working with\nasynchronous or otherwise blocking work in Rust (wasm), and provides the ability to interoperate\nwith JavaScript events and JavaScript I/O primitives.\n\nThere are three main interfaces in this crate currently:\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   A type that is constructed with a [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html)\n   and can then be used as a `Future<Output=Result<JsValue, JsValue>>`. This `Future` will resolve to `Ok` if\n   the `Promise` is resolved and `Err` if the `Promise` is rejected, containing the resolved or rejected\n   value from the `Promise` respectively.\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Converts a Rust `Future<Output=Result<JsValue, JsValue>>` into a\n   JavaScript `Promise`. The future’s result will translate to either a resolved or rejected\n   `Promise` in JavaScript.\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   Spawns a `Future<Output = ()>` on the current thread. This is the best way\n   to run a Future in Rust without sending it to JavaScript.\n\n_[`wasm-bindgen-futures` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` is going to be the most commonly used part of the `wasm-bindgen-futures` crate in Yew\nas this helps when using libraries that have async APIs.\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // console log \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew has also added support for futures in certain APIs, most notably you can create a\n`callback_future` which accepts an `async` block - this uses `spawn_local` internally.\n\n_[`spawn_local` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'The web-sys crate provides bindings for Web APIs.'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs. This is\nprocedurally generated from browser WebIDL which is why some names are so long and why some types are vague.\n\n## Features in `web-sys`\n\nThe `web-sys` crate with all of its features enabled can add lots of bloat to a Wasm application.\nTo get around this issue most types are feature gated so that you only include the types\nyou require for your application. Yew enables several features from `web-sys` and\nexposes some types in its public API. You will often need to add `web-sys` as a dependency yourself.\n\n## Inheritance in `web-sys`\n\nIn the [Simulating inheritance section](./wasm-bindgen.mdx#simulating-inheritance) you can read how in\ngeneral Rust provides an approach to simulate inheritance in JavaScript. This is very important in\n`web-sys` as understanding what methods are available on a type means understanding its inheritance.\n\nThis section is going to look at a specific element and list out its inheritance using Rust by\ncalling [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) until\nthe value is [`JsValue`](./wasm-bindgen.mdx#jsvalue):\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement is <textarea> in html.\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // Notice we have moved from web-sys types now into built-in\n    // JavaScript types which are in the js-sys crate.\n    let object: &js_sys::Object = event_target.deref();\n\n    // Notice we have moved from js-sys type to the root JsValue from\n    // the wasm-bindgen crate.\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // Using deref like this means we have to manually traverse\n    // the inheritance tree, however, you can call JsValue methods\n    // on the HtmlTextAreaElement type.\n    // The `is_string` method comes from JsValue.\n    assert!(!text_area.is_string());\n\n    // empty function just to prove we can pass HtmlTextAreaElement as a\n    // &EventTarget.\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // The compiler will walk down the deref chain in order to match the types here.\n    this_function_only_takes_event_targets(&text_area);\n\n    // The AsRef implementations allow you to treat the HtmlTextAreaElement\n    // as an &EventTarget.\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[Inheritance in `web-sys` in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)._\n\n## The `Node` in `NodeRef`\n\nYew uses a [`NodeRef`](concepts/function-components/node-refs.mdx) to provide a way for keeping a reference to\na `Node` made by the [`html!`](concepts/html/introduction.mdx) macro. The `Node` part of `NodeRef` is referring to\n[`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html). The\n`NodeRef::get` method will return a `Option<Node>` value, however, most of the time in Yew you want\nto cast this value to a specific element so you can use its specific methods. This casting\ncan be done using [`JsCast`](./wasm-bindgen.mdx#JsCast) on the `Node` value, if present, but Yew\nprovides the `NodeRef::cast` method to perform this casting for convenience and so that you do not\nnecessarily have to include the `wasm-bindgen` dependency for the `JsCast` trait.\n\nThe two code blocks below do essentially the same thing, the first is using `NodeRef::cast` and\nthe second is using [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\non the `web_sys::Node` returned from `NodeRef::get`.\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript example to Rust\n\nThis section demonstrates examples of how JavaScript code which interact with the\nWeb APIs can be rewritten with `web-sys` in Rust.\n\n### JavaScript example\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e = Mouse event.\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left //x position within the element.\n    var y = e.clientY - rect.top //y position within the element.\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` example\n\nUsing `web-sys` alone the above JavaScript example could be implemented like this:\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable all the web-sys features we want to use!\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// we now need to save the `mousemove` Closure so that when\n// this event fires the closure is still in memory.\n```\n\nThis version is much more verbose, but you will probably notice part of that is because of failure\ntypes reminding us that some of these function calls have invariants that must be held, or otherwise will\ncause a panic in Rust. Another part of the verbosity is the calls to `JsCast` to cast into\ndifferent types so that you can call its specific methods.\n\n### Yew example\n\nIn Yew you will mostly be creating [`Callback`](concepts/function-components/callbacks.mdx)s to use in the\n[`html!`](concepts/html/introduction.mdx) macro so the example is going to use this approach instead of completely copying\nthe approach above:\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable the `DomRect` feature to use the\n# `get_bounding_client_rect` method.\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## External libraries\n\n`web-sys` is a raw binding to the Web API so it comes with some pain in Rust because it was not\ndesigned with Rust or even a strong type system in mind, this is where community crates\nprovide abstractions over `web-sys` to provide more idiomatic Rust APIs.\n\n_[External libraries page](/community/external-libs)_\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\nCallbacks are used to asynchronously communicate upwards the components tree and with other things like agents or the DOM during event handling.\nInternally their type is just an `Fn` wrapped in `Rc` to allow them to be cheaply cloned.\n\nThey have an `emit` function if you want to call them manually.\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\")); // call the callback\n// web_sys::console::log_1(&result.into()); // if uncommented will print \"Bye Bob\"\n```\n\n## Passing callbacks as props\n\nA common pattern in yew is to create a callback and pass it down as a prop.\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// Then supply the prop\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM Events and Callbacks\n\nCallbacks are also used to hook into DOM events.\n\nFor example, here we define a callback that will be called when the user clicks the button:\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // the field name `children` is important!\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n    // highlight-next-line\n            { props.children.clone() } // you can forward children like this\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'Communication between components'\n---\n\n## Parent to child messaging\n\nPass data as [props](./properties) that cause a re-render, this is the way to pass messages to children.\n\n## Child to parent messaging\n\nPass down a callback via props, that the child on an event can call. [Example](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'Generic Components'\ndescription: 'The #[component] attribute'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `#[component]` attribute also works with generic functions for creating generic components.\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// then can be used like this\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// or\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'Custom Hooks'\n---\n\n## Defining custom Hooks\n\nThe stateful logic of a component can be extracted into reusable functions by creating custom Hooks.\n\nConsider that we wish to create an event listener that listens to an event on the `window`\nobject.\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nThere's one problem with this code: the logic can't be reused by another component.\nIf we build another component that listens to a different event,\ninstead of copying the code, we can move the logic into a custom hook.\n\nWe'll start by creating a new function called `use_event`.\nThe `use_` prefix denotes that a function is a hook.\nThis function will take an event target, an event type, and a callback.\nAll hooks must be marked by `#[hook]` on their function definition.\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nThis simple hook can be created by composing built-in hooks. For this example, we'll use the\n`use_effect_with` hook, so an event listener can be recreated when the hook arguments change.\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nAlthough this approach works in almost all cases, it can't be used to write primitive hooks like the pre-defined hooks we've been using already.\n\nView the docs on [docs.rs](https://docs.rs/yew) for documentation and `hooks` directory to see implementations of pre-defined hooks.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks are functions that let you store state and perform side effects.\n\nYew comes with a few pre-defined hooks. You can also create your own or discover many [community-made hooks](/community/awesome#hooks).\n\n## Rules of hooks\n\n1. A hook function name always has to start with `use_`\n2. Hooks can only be used in the following locations:\n    - Top-level of a function/hook.\n    - Blocks inside a function/hook, given it is not already branched.\n    - In the condition of a top-level `if` expression inside a function/hook.\n    - In the scrutinee of a top-level `match` expression inside a function/hook.\n3. Hooks must be called in the same order for every render. Returning early is only allowed when using [Suspense](../../suspense.mdx)\n\nThese rules are enforced by either compile-time or run-time errors.\n\n### Pre-defined Hooks\n\nYew comes with the following predefined Hooks:\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nThe documentation for these hooks can be found in the [Yew API docs](https://yew-rs-api.web.app/next/yew/functional/)\n\n### Custom Hooks\n\nThere are cases where you want to define your own Hooks to encapsulate potentially stateful logic from a component into reusable functions.\nSee the [Defining custom hooks](concepts/function-components/hooks/custom-hooks.mdx#defining-custom-hooks) section for more information.\n\n## Further reading\n\n- The React documentation has a section on [React hooks](https://reactjs.org/docs/hooks-intro.html).\n  These are not the same as Yew's hooks, but the underlying concept is similar.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'Node Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` attribute can be used to attach the `NodeRef` to an HTML element. In callbacks,\nyou can then get the DOM `Element` that the ref is attached to. This can be used to make\nchanges to the DOM outside of the `view` lifecycle method, retrieve the value of an `<input>`\nand other direct interactions with the DOM via the javascript API.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\n\n:::caution\nDo not manually modify the DOM tree that is rendered by Yew. Treat the `NodeRef` as a read-only\naccess, if you are unsure.\n:::\n\n## Further Reading\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` example](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nProperties are often shortened as \"Props\".\n\n:::\n\nProperties are essentially component arguments that Yew can keep watch on.\n\nA type has to implement the `Properties` trait before it can be used as the properties of a component.\n\n## Reactivity\n\nYew checks if props have changed when reconciling the Virtual DOM during re-rendering, to know if nested components need to be re-rendered.\nThis way Yew can be considered a very reactive framework, as changes from the parent will always be propagated downward,\nand the view will never be out of sync with the data coming from props/state.\n\n:::tip\n\nIf you have not yet completed the [tutorial](../../tutorial), try it out and test this reactivity yourself!\n\n:::\n\n## Derive macro\n\nYew provides a derive macro to easily implement the `Properties` trait on structs.\n\nTypes for which you derive `Properties` must also implement `PartialEq` so Yew can do data comparison.\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## Use in function components\n\nThe attribute `#[component]` allows to optionally receive Props in the function arguments. To supply them,\nthey are assigned via attributes in the `html!` macro.\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// Then supply the prop\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// No props to supply\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## Derive macro field attributes\n\nWhen deriving `Properties` all fields are required by default.\nThe following attributes allow you to give your props default values which will be used when the parent has not set them.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`. The expression\nis evaluated when the properties are constructed and no explicit value has been given.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\nThe function is called when no explicit value has been given for that attribute.\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a shared pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // Notice we did not need to specify name prop\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## Automatically generate properties (yew-autoprops)\n\nIn order to streamline your development process, you can also use the macro\n`#[autoprops]` (from the crate `yew-autoprops`) that will automatically\ngenerate the `Properties` struct for you.\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// the #[autoprops] macro must appear BEFORE #[component], the order matters\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// The properties struct \"GreetingsProps\" will be generated automatically.\n//\n// `is_loading` will be passed as value to the components while `message` and\n// `name` will use references because of the leading `&` in the definition.\n```\n\n## Evaluation Order\n\nProps are evaluated in the order they're specified, as shown by the following example:\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nlet mut g = 1..=3;\nlet props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\nassert_eq!(props.first, 1);\nassert_eq!(props.second, 2);\nassert_eq!(props.last, 3);\n```\n\n## Anti Patterns\n\nWhile almost any Rust type can be passed as properties, there are some anti-patterns that should be avoided.\nThese include, but are not limited to:\n\n1. Using `String` type instead of `AttrValue`. <br />\n   **Why is this bad?** `String` can be expensive to clone.\n   Cloning is often needed when the prop value is used with hooks and callbacks. `AttrValue` is either\n   a reference-counted string (`Rc<str>`) or a `&'static str`, thus very cheap to clone.<br />\n   **Note**: `AttrValue` internally is `IString` from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n2. Using interior mutability. <br />\n   **Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should\n   _generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when the state has changed)\n   so you may have to manually force a render. Like all things, it has its place. Use it with caution.\n3. Using `Vec<T>` type instead of `IArray<T>`. <br />\n   **Why is this bad?** `Vec<T>`, just like `String`, can also be expensive to clone. `IArray<T>` is either\n   a reference-counted slice (`Rc<[T]>`) or a `&'static [T]`, thus very cheap to clone.<br />\n   **Note**: `IArray` can be imported from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n4. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue\n   or PR a fix to this documentation.\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) is an experimental package that allows one to create the Props struct on the fly out of the arguments of your function. Might be useful, if the properties struct is never reused.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: 'Pure Components'\n---\n\nA function component is considered [pure] when the returned `Html` is deterministically derived\nfrom its props when its view function does not mutate its state or has other side effects.\n\n[pure]: https://en.wikipedia.org/wiki/Pure_function\n\nThe example below is a pure component. For a given prop `is_loading` it will always result in the same `Html` without any side effects.\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\nIf you have an internal pure component that makes no use of hooks and other component machinery, you can often write it instead\nas a normal function returning `Html` and avoid a bit of overhead for Yew, related to running the component lifecycle. Use\n[expression syntax](concepts/html/literals-and-expressions.mdx#expressions) to render them in `html!`.\n:::\n\n## Impure components\n\nYou might wonder if a component can be impure if it does not use any globals, since it is just a function that is called every render.\nThis is where the next topic comes in - [hooks](./hooks)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/function-components/state.mdx",
    "content": "---\ntitle: 'State'\n---\n\n## General view of how to store state\n\nThis table can be used as a guide when deciding what state-storing type fits best for your use case:\n\n| Hook                     | Type                       | Rerender when?               | Scope               |\n| ------------------------ | -------------------------- | ---------------------------- | ------------------- |\n| [use_state]              | `T`                        | got set                      | component instance  |\n| [use_state_eq]           | `T: PartialEq`             | got set with diff. value     | component instance  |\n| [use_reducer]            | `T: Reducible`             | got reduced                  | component instance  |\n| [use_reducer_eq]         | `T: Reducible + PartialEq` | got reduced with diff. value | component instance  |\n| [use_memo]               | `Deps -> T`                | dependencies changed         | component instance  |\n| [use_callback]           | `Deps -> Callback<E>`      | dependencies changed         | component instance  |\n| [use_mut_ref]            | `T`                        | -                            | component instance  |\n| a static global variable | `T`                        | -                            | global, used by all |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/classes.mdx",
    "content": "---\ntitle: 'Classes'\ndescription: 'A handy macro to handle classes'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Classes\n\nThe struct `Classes` can be used to deal with HTML classes.\n\nWhen pushing a string to the set, `Classes` ensures that there is one element\nfor every class even if a single string might contain multiple classes.\n\n`Classes` can also be merged by using `Extend` (i.e.\n`classes1.extend(classes2)`) or `push()` (i.e. `classes1.push(classes2)`).\nAny type that implements `Into<Classes>` can be pushed onto an existing `Classes`.\n\nThe macro `classes!` is a convenient macro that creates one single `Classes`.\nIts input accepts a comma-separated list of expressions. The only requirement\nis that every expression implements `Into<Classes>`.\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Components that accept classes\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/components.mdx",
    "content": "---\ntitle: 'Components'\ndescription: 'Create complex layouts with component hierarchies'\n---\n\n## Basic\n\nComponents can be used in the `html!` macro:\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // With the whole set of props provided at once\n        <MyComponentWithProps ..props.clone() />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## Nested\n\nComponents can accept child components/elements if they have a `children` field in their `Properties`\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\nThe `html!` macro allows you to pass a base expression with the `..props` syntax instead of specifying each property individually,\nsimilar to Rust's [Functional Update Syntax](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax).\nThis base expression must occur after any individual props are passed.\nWhen passing a base props expression with a `children` field, the children passed in the `html!` macro overwrite the ones already present in the props.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // props.children will be overwritten with this\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## Relevant examples\n\n- [Function Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [Function Router](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: 'Conditional rendering'\ndescription: 'Rendering nodes conditionally in html!'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If blocks\n\nTo conditionally render some markup, we wrap it in an `if` block:\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/elements.mdx",
    "content": "---\ntitle: 'Elements'\ndescription: 'Both HTML and SVG elements are supported'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM nodes\n\nThere are many reasons why you might want to create or manage DOM nodes manually in Yew, such as\nwhen integrating with JS libraries that can cause conflicts with managed components.\n\nUsing `web-sys`, you can create DOM elements and convert them into a `Node` - which can then be\nused as an `Html` value using `VRef`:\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // memoize as this only needs to be executed once\n    let node = use_memo(\n        (),\n        |_| {\n            // Create a div element from the document\n            let div: Element = document().create_element(\"div\").unwrap();\n            // Add content, classes etc.\n            div.set_inner_html(\"Hello, World!\");\n            // Convert Element into a Node\n            let node: Node = div.into();\n            // Return that Node as a Html value\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo return Rc so we need to deref and clone\n    (*node).clone()\n}\n\n```\n\n## Dynamic tag names\n\nWhen building a higher-order component you might find yourself in a situation where the element's tag name is not static.\nFor example, you might have a `Title` component that can render anything from `h1` to `h6` depending on a level prop.\nInstead of having to use a big match expression, Yew allows you to set the tag name dynamically\nusing `@{name}` where `name` can be any expression that returns a string.\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## Boolean Attributes\n\nSome content attributes (e.g checked, hidden, required) are called boolean attributes. In Yew,\nboolean attributes need to be set to a bool value:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nThis will result in **HTML** that is functionally equivalent to this:\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\nSetting a boolean attribute to false is equivalent to not using the attribute at all; values from\nboolean expressions can be used:\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nThis will result in the following **HTML**:\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## String-like attributes\n\nBut apart from a select few boolean attributes, you will probably be dealing with a lot of string-like HTML attributes and Yew has a few options to pass string-like values to components.\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nThey are all valid **but** we encourage you to favor Yew's custom `AttrValue`, especially if you need to clone or pass them as properties to another component.\n\n## Optional attributes for HTML elements\n\nMost HTML attributes can use optional values (Some(x) or None). This allows us to omit the attribute if the attribute is marked as optional.\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\nIf the attribute is set to `None`, the attribute will not be set in the DOM.\n\n## Children\n\nMost HTML elements accept arbitrary HTML as children, however, there is a set of them that doesn't accept any children at all.\nThese elements are called _void_ elements, and they are:\n\n- `<area />`\n- `<base />`\n- `<base />`\n- `<br />`\n- `<col />`\n- `<embed />`\n- `<hr />`\n- `<img />`\n- `<input />`\n- `<link />`\n- `<meta />`\n- `<param />`\n- `<source />`\n- `<track />`\n- `<wbr />`\n- `<textarea />`\n\nAttempting to provide children to these elements will result in a compilation error or, if the element tag is chosen dynamically, in a panic.\n\n### The case of `<textarea>`\n\nThe `<textarea>` element is special; The modern HTML specification states that children of `<textarea>` define its default value, however in Yew it's specified differently.\nInstead of writing\n\n```html\n<textarea>{\"default value\"}</textarea>\n```\n\nWhich would fail to compile, it's customary to write\n\n```html\n<textarea defaultvalue=\"default value\" />\n```\n\n## Relevant examples\n\n- [Inner HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/events.mdx",
    "content": "---\ntitle: 'Events'\n---\n\n## Introduction\n\nYew integrates with the [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate and\nuses the events from that crate. The [table below](#event-types) lists all of the `web-sys`\nevents that are accepted in the `html!` macro.\n\nYou can still add a [`Callback`](../function-components/callbacks.mdx) for an event that is not listed in the table\nbelow, see [Manual event listener](#manual-event-listener).\n\n## Event Types\n\n:::tip\nAll the event types mentioned in the following table are re-exported under `yew::events`.\nUsing the types from `yew::events` makes it easier to ensure version compatibility than\nif you were to manually include `web-sys` as a dependency in your crate because you will not\nend up using a version which conflicts with the version that Yew specifies.\n:::\n\nThe event listener name is the expected name when adding an event `Callback` in the `html` macro:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nThe event name is the listener without the \"on\" prefix, therefore, the `onclick` event listener\nlistens for `click` events. See the end of this page for a [full list of available event](#available-events) with their types.\n\n## Event bubbling {#event-bubbling}\n\nEvents dispatched by Yew follow the virtual DOM hierarchy when bubbling up to listeners. Currently, only the bubbling phase\nis supported for listeners. Note that the virtual DOM hierarchy is most often, but not always, identical to the actual\nDOM hierarchy. The distinction is important when working with [portals](../../advanced-topics/portals) and other\nmore advanced techniques. The intuition for well-implemented components should be that events bubble from children\nto parents. In this way the hierarchy in your coded `html!` is the one observed by event handlers.\n\nIf you are not interested in event bubbling, you can turn it off by calling\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n_before_ starting your app. This speeds up event handling, but some components may break from not receiving the events they expect.\nUse this with care!\n\n## Event delegation\n\nIt can be surprising that event listeners are _not_ directly registered on the element where they are rendered. Instead, events\nare delegated from the subtree root of the Yew app. Still, events are delivered in their native form, and no synthetic\nform is created. This can lead to mismatches between the event you would expect in HTML listeners and those showing up in Yew.\n\n- [`Event::current_target`] points to the Yew subtree root instead of the element the listener is added on. Use\n  [`NodeRef`](../function-components/node-refs.mdx) if you want access to the underlying `HtmlElement`.\n- [`Event::event_phase`] is always [`Event::CAPTURING_PHASE`]. Internally, the event will behave as if it was in the bubbling\n  phase, the event propagation is replayed and the event [bubbles _up_](#event-bubbling), i.e. event listeners higher up in\n  the virtual DOM will trigger _after_ event listeners below them. Currently, capturing listeners is not supported by Yew.\n\n    This also means that events registered by Yew will usually fire before other event listeners.\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## Typed event target\n\n:::caution\nIn this section **target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))**\nis always referring to the element at which the event was dispatched from.\n\nThis will **not** always be the element at which the `Callback` is placed.\n:::\n\nIn event `Callback`s you may want to get the target of that event. For example, the\n`change` event gives no information but is used to notify that something has changed.\n\nIn Yew getting the target element in the correct type can be done in a few ways and we will go through\nthem here. Calling [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)\non an event returns an optional [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html)\ntype, which might not seem very useful when you want to know the value of your input element.\n\nIn all the approaches below we are going to tackle the same problem, so it is clear where the approach\ndiffers as opposed to the problem at hand.\n\n**The Problem:**\n\nWe have an `onchange` `Callback` on my `<input>` element and each time it is invoked we want to send\nan [update](components#update) `Msg` to our component.\n\nOur `Msg` enum looks like this:\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### Using `JsCast`\n\nThe [`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate has\na useful trait: [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html),\nwhich allows us to hop and skip our way to the type we want, as long as it implements `JsCast`. We can\ndo this cautiously, which involves some runtime checks and failure types like `Option` and `Result`,\nor we can do it dangerously.\n\nEnough talk, more code:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# need wasm-bindgen for JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // When events are created the target is undefined, it's only\n            // when dispatched does the target get added.\n            let target: Option<EventTarget> = e.target();\n            // Events can bubble so this listener might catch events from child\n            // elements which are not of type HtmlInputElement\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        // Here we are sure that this is input element so we can convert it to the appropriate type without checking\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nThe methods from `JsCast` are [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nand [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)\nand you can probably see, they allowed\nus to go from `EventTarget` to [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html).\nThe `dyn_into` method is cautious because at\nruntime it will check whether the type is actually a `HtmlInputElement` and if not return an\n`Err(JsValue)`, the [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\nis a catch-all type and is essentially giving you back the object to try again.\n\nAt this point you might be thinking... when is the dangerous version ok to use? In the case above it\nis safe<sup>1</sup> as we've set the `Callback` on to an element with no children so the target can\nonly be that same element.\n\n_<sup>1</sup> As safe as anything can be when JS land is involved._\n\n### Using `TargetCast`\n\n**It is highly recommended to read [Using JsCast](#using-jscast) first!**\n\n:::note\n`TargetCast` was designed to feel very similar to `JsCast` - this is to allow new users to get a feel\nfor the behaviour of `JsCast` but with the smaller scope of events and their targets.\n\n`TargetCast` vs `JsCast` is purely preference, you will find that `TargetCast` implements something\nsimilar to what you would using `JsCast`.\n:::\n\nThe `TargetCast` trait is built on top of `JsCast` and is specialized towards getting typed event\ntargets from events.\n\n`TargetCast` comes with Yew so no need to add a dependency in order to use the trait methods on events\nbut it works in a very similar way to `JsCast`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nIf you followed the advice above and read about `JsCast`, or know the trait, you can probably\nsee that `TargetCast::target_dyn_into` feels similar to `JsCast::dyn_into` but specifically\ndoes the cast on the target of the event. `TargetCast::target_unchecked_into` is similar to\n`JsCast::unchecked_into`, and as such all the same warnings above `JsCast` apply to `TargetCast`.\n\n### Using `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) can be used instead of querying the event given to a `Callback`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nUsing `NodeRef`, you can ignore the event and use the `NodeRef::cast` method to get an\n`Option<HtmlInputElement>` - this is optional as calling `cast` before the `NodeRef` has been\nset, or when the type doesn't match will return `None`.\n\nYou might also see by using `NodeRef` we don't have to send the `String` back into state as we always access to `input_node_ref` - so we could do the following:\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // do something with value\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nWhich approach you take depends on your component and your preferences, there is no _blessed_ way\nper se.\n\n## Manual event listener\n\nYou may want to listen to an event that is not supported by Yew's `html` macro, see the\n[supported events listed here](#event-types).\n\nIn order to add an event listener to one of elements manually we need the help of\n[`NodeRef`](../function-components/node-refs.mdx) so that in `use_effect_with` we can add a listener using the\n[`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) and\n[wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API.\n\nThe examples below are going to show adding listeners for the made-up `custard` event. All events\neither unsupported by yew or custom can be represented as a\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html). If you\nneed to access a specific method or field on a custom / unsupported event then you can use the\nmethods of [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nin order to convert to the type required.\n\n### Using `Closure` (verbose)\n\nUsing the `web-sys` and `wasm-bindgen` API's directly for this can be a bit painful.. so brace\nyourself ([there is a more concise way thanks to `gloo`](#using-gloo-concise)).\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `Closures`, see\n[The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html).\n\n### Using `gloo` (concise)\n\nThe easier way is with `gloo`, more specifically [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)\nwhich is an abstraction for `web-sys`, `wasm-bindgen`.\n\n`gloo_events` has the `EventListener` type which can be used to create and store the\nevent listener.\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `EventListener`, see the\n[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html).\n\n## Full list of available events {#available-events}\n\n| Event listener name         | `web_sys` Event Type                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/fragments.mdx",
    "content": "---\ntitle: 'Fragments'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro always requires a single root node. To get around this restriction, you\ncan use an \"empty tag\" (these are also called \"fragments\").\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// error: only one root html element allowed\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'The procedural macro for generating HTML and SVG'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro allows you to write HTML and SVG code declaratively. It is similar to JSX\n(an extension to JavaScript that allows you to write HTML-like code inside of JavaScript).\n\n**Important notes**\n\n1. The `html!` macro only accepts one root html node (you can counteract this by using\n   [fragments](./fragments.mdx) or [iterators](./../html/lists.mdx))\n2. An empty `html! {}` invocation is valid and will not render anything\n3. Literals must always be quoted and wrapped in braces: `html! { <p>{ \"Hello, World\" }</p> }`\n4. The `html!` macro will make all tag names lowercase. To use upper case characters (which are required for some SVG elements) use [dynamic tag names](concepts/html/elements.mdx#dynamic-tag-names): `html! { <@{\"myTag\"}></@> }`\n\n:::note\nThe `html!` macro can reach the default recursion limit of the compiler. If you encounter compilation errors,\nadd an attribute like `#![recursion_limit=\"1024\"]` in the crate root to overcome the problem.\n:::\n\n## Tag Structure\n\nTags are based on HTML tags. Components, Elements, and Lists are all based on this tag syntax.\n\nTags must either self-close `<... />` or have a corresponding end tag for each start tag.\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\nFor convenience, elements which _usually_ require a closing tag are **allowed** to self-close. For example, writing `html! { <div class=\"placeholder\" /> }` is valid.\n:::\n\n## Children\n\nCreate complex nested HTML and SVG layouts with ease:\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nIf you compile Yew using a nightly version of the Rust compiler, the macro will warn you about some\ncommon pitfalls that you might run into. Of course, you may need to use the stable compiler (e.g.\nyour organization might have a policy mandating it) for release builds, but even if you're using a\nstable toolchain, running `cargo +nightly check` might flag some ways that you could improve your\nHTML code.\n\nAt the moment the lints are mostly accessibility-related. If you have ideas for lints, please feel\nfree to [chime in on this issue](https://github.com/yewstack/yew/issues/1334).\n\n## Specifying attributes and properties\n\nAttributes are set on elements in the same way as in normal HTML:\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\nProperties are specified with `~` before the element name:\n\n```rust , ignore\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\nThe braces around the value can be omitted if the value is a literal.\n\n:::\n\n:::note What classifies as a literal\n\nLiterals are all valid [literal expressions](https://doc.rust-lang.org/reference/expressions/literal-expr.html)\nin Rust. Note that [negative numbers are **not** literals](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)\nand thus must be enclosed in curly-braces `{-6}`\n\n:::\n\n:::note Component properties\nComponent properties are passed as Rust objects and are different from the element attributes/properties described here.\nRead more about them at [Component Properties](../function-components/properties.mdx)\n:::\n\n### Special properties\n\nThere are special properties which don't directly influence the DOM but instead act as instructions to Yew's virtual DOM.\nCurrently, there are two such special props: `ref` and `key`.\n\n`ref` allows you to access and manipulate the underlying DOM node directly. See [Refs](../function-components/node-refs.mdx) for more details.\n\n`key` on the other hand gives an element a unique identifier which Yew can use for optimization purposes.\n\n:::info\nRead more at [Lists](./html/lists)\n:::\n\n## Comments\n\nIt is also possible to use Rust style comments as part of the HTML structure:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <>\n    <h1>{ \"My heading\" }</h1>\n    // here comes the content\n    <main>\n      { \"…\" }\n    </main>\n  </>\n};\n```\n\nComments will be dropped during the parsing process and will not end up in the final output.\n\n## Conditional Rendering\n\nMarkup can be rendered conditionally by using Rust's conditional structures. ' +\n'Currently only `if` and `if let` are supported.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\nRead more at [Conditional Rendering](./conditional-rendering.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/lists.mdx",
    "content": "---\ntitle: 'Lists'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Iterators\n\nThere are 3 ways to build HTML from iterators:\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` loops\">\nThe main approach is to use for loops, the same for loops that already exist in Rust, but with 2 key differences:\n1. Unlike standard for loops which can't return anything, for loops in `html!` are converted to a list of nodes;\n2. Diverging expressions, i.e. `break`, `continue` are not allowed in the body of for loops in `html!`.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` block\">\nAn alternative is to use the `for` keyword, which is not native Rust syntax and instead is used by\nthe HTML macro to output the needed code to display the iterator.\nThis approach is better than the first one when the iterator is already computed and the only thing left to do\nis to pass it to the macro.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` method\">\n\nThe last is to call `collect::<Html>()` on the final transform in your iterator, which returns a\nlist that Yew can display.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Keyed lists\n\nA keyed list is an optimized list that has keys on **all** children.\n`key` is a special prop provided by Yew that gives an HTML element or component a unique identifier\nthat is used for optimization purposes inside Yew.\n\n:::caution\nKey has to be unique only in each list, in contrast to the global uniqueness of HTML `id`s. It must not depend on the order of the list.\n:::\n\nIt is always recommended to add keys to lists.\n\nKeys can be added by passing a unique `String`, `str` or integer to the special `key` prop:\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### Performance increases\n\nWe have [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list) example that lets you test the performance improvements, but here is a rough rundown:\n\n1. Go to [Keyed list hosted demo](https://examples.yew.rs/keyed_list)\n2. Add 500 elements.\n3. Disable keys.\n4. Reverse the list.\n5. Look at \"The last rendering took Xms\" (At the time of writing this it was ~60ms)\n6. Enable keys.\n7. Reverse the list.\n8. Look at \"The last rendering took Xms\" (At the time of writing this it was ~30ms)\n\nSo just at the time of writing this, for 500 components it is a 2x increase of speed.\n\n### Detailed explanation\n\nUsually, you just need a key on every list item when you iterate and the order of data can change.\nIt's used to speed up the reconciliation process when re-rendering the list.\n\nWithout keys, assume you iterate through `[\"bob\", \"sam\", \"rob\"]`, ending up with the HTML:\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\nThen on the next render, if your list changed to `[\"bob\", \"rob\"]`, yew could delete\nthe element with id=\"rob\" and update id=\"sam\" to be id=\"rob\"\n\nIf you had added a key to each element, the initial HTML would be the same, but after\nthe render with the modified list, `[\"bob\", \"rob\"]`, yew would just delete the second\nHTML element and leave the rest untouched since it can use the keys to associate them.\n\nIf you ever encounter a bug/\"feature\" where you switch from one component to another but both have a div as the highest rendered element.\nYew reuses the rendered HTML div in those cases as an optimization.\nIf you need that div to be recreated instead of reused, then you can add different keys and they will not be reused.\n\n## Further reading\n\n- [TodoMVC](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'Literals and Expressions'\n---\n\n## Literals\n\nIf expressions resolve to types that implement `Display`, they will be converted to strings and inserted into the DOM as a [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) node.\n:::note\nString literals create `Text` nodes, which are treated as strings by the browser. Hence, even if the expression contains a `<script>` tag you can't fall for XSS and such security issues, unless of course you wrap the expression in a `<script>` block.\n:::\n\nAll display text must be enclosed by `{}` blocks because the text is handled as an expression. This is\nthe largest deviation from normal HTML syntax that Yew makes.\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## Expressions\n\nYou can insert expressions in your HTML using `{}` blocks, as long as they resolve to `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\nIt often makes sense to extract these expressions into functions or closures to optimize for readability:\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/router.mdx",
    "content": "---\ntitle: 'Router'\ndescription: \"Yew's official router\"\n---\n\nRouters in Single Page Applications (SPA) handle displaying different pages depending on what the URL is. Instead of the\ndefault behavior of requesting a different remote resource when a link is clicked, the router instead sets the URL\nlocally to point to a valid route in your application. The router then detects this change and then decides what to\nrender.\n\nYew provides router support in the `yew-router` crate. To start using it, add the dependency to your `Cargo.toml`:\n\n```sh\ncargo add yew-router\n```\n\nThe utilities needed are provided under `yew_router::prelude`,\n\n## Usage\n\nYou start by defining a `Route`.\n\nRoutes are defined as an `enum` which derives `Routable`. This enum must be `Clone + PartialEq`.\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\nA `Route` is paired with a `<Switch />` component, which finds the variant whose path matches the browser's\ncurrent URL and passes it to the `render` callback. The callback then decides what to render. In case no path is\nmatched, the router navigates to the path with `not_found` attribute. If no route is specified, nothing is rendered, and\na message is logged to the console stating that no route was matched.\n\nMost of yew-router's components, in particular `<Link />` and `<Switch />`, must be (grand-)children of one of the Router components\n(e.g. `<BrowserRouter />`). You usually only need a single Router in your app, most often rendered immediately by your most top-level `<App />`\ncomponent. The Router registers a context, which is needed for Links and Switches to function. An example is shown below.\n\n:::caution\nWhen using `yew-router` in a browser environment, `<BrowserRouter />` is highly recommended.\nYou can find other router flavors in the [API Reference](https://docs.rs/yew-router/).\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### Path Segments\n\nIt is also possible to extract information from a route using dynamic and named wildcard segments.\nYou can then access the post's id inside `<Switch />` and forward it to the appropriate component via properties.\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\nYou can have a normal `Post` variant instead of `Post {id: String}` too. For example, when `Post` is rendered\nwith another router, the field can then be redundant as the other router can match and handle the path. See the\n[Nested Router](#nested-router) section below for details\n:::\n\nNote the fields must implement `Clone + PartialEq` as part of the `Route` enum. They must also implement\n`std::fmt::Display` and `std::str::FromStr` for serialization and deserialization. Primitive types like integer, float,\nand String already satisfy the requirements.\n\nIn case when the form of the path matches, but the deserialization fails (as per `FromStr`). The router will consider\nthe route as unmatched and try to render the not found route (or a blank page if the not found route is unspecified).\n\nConsider this example:\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch function renders News and id as is. Omitted here.\n```\n\nWhen the segment goes over 255, `u8::from_str()` fails with `ParseIntError`, the router will then consider the route\nunmatched.\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\nFor more information about the route syntax and how to bind parameters, check\nout [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params).\n\n### Location\n\nThe router provides a universal `Location` struct via context which can be used to access routing information.\nThey can be retrieved by hooks or convenient functions on `ctx.link()`.\n\n### Navigation\n\n`yew_router` provides a handful of tools to work with navigation.\n\n#### Link\n\nA `<Link />` renders as an `<a>` element, the `onclick` event handler will call\n[preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault), and push the targeted page to the\nhistory and render the desired page, which is what should be expected from a Single Page App. The default `onclick` of a\nnormal anchor element would reload the page.\n\nThe `<Link />` component also passes its children to the `<a>` element. Consider it a replacement of `<a/>` for in-app\nroutes. Except you supply a `to` attribute instead of a `href`. An example usage:\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\nStruct variants work as expected too:\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### Navigator API\n\nNavigator API is provided for both function components and struct components. They enable callbacks to change the\nroute. A `Navigator` instance can be obtained in either case to manipulate the route.\n\n##### Function Components\n\nFor function components, the `use_navigator` hook re-renders the component when the underlying navigator provider changes.\nHere is how to implement a button that navigates to the `Home` route when clicked.\n\n```rust ,ignore\n#[component(MyComponent)]\npub fn my_component() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <>\n            <button {onclick}>{\"Click to go home\"}</button>\n        </>\n    }\n}\n```\n\n:::caution\nThe example here uses `Callback::from`. Use a normal callback if the target route can be the same as the route\nthe component is in, or just to play safe. For example, consider a logo button on every page that goes back to the\nhome page when clicked. Clicking that button twice on the home page causes the code to panic because the second click pushes an\nidentical Home route and the `use_navigator` hook will not trigger a re-render.\n:::\n\nIf you want to replace the current location instead of pushing a new location onto the stack, use `navigator.replace()`\ninstead of `navigator.push()`.\n\nYou may notice `navigator` has to move into the callback, so it cannot be used again for other callbacks. Luckily `navigator`\nimplements `Clone`, here is for example how to have multiple buttons for different routes:\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### Struct Components\n\nFor struct components, the `Navigator` instance can be obtained through the `ctx.link().navigator()` API. The rest is\nidentical to the function component case. Here is an example of a view function that renders a single button.\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### Redirect\n\n`yew-router` also provides a `<Redirect />` component in the prelude. It can be used to achieve similar effects as the\nnavigator API. The component accepts a\n`to` attribute as the target route. When a `<Redirect/>` is rendered users will be redirected to the route specified in props.\nHere is an example:\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // made-up hook `use_user`\n    let user = match use_user() {\n        Some(user) => user,\n        // Redirects to the login page when user is `None`.\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... actual page content.\n}\n```\n\n:::tip `Redirect` vs `Navigator`, which to use\nThe Navigator API is the only way to manipulate route in callbacks.\nWhile `<Redirect />` can be used as return values in a component. You might also want to use `<Redirect />` in another\nnon-component context, for example in the switch function of a [Nested Router](#nested-router).\n:::\n\n### Listening to Changes\n\n#### Function Components\n\nYou can use `use_location` and `use_route` hooks. Your components will re-render when\nprovided values change.\n\n#### Struct Components\n\nIn order to react on route changes, you can pass a callback closure to the `add_location_listener()` method of `ctx.link()`.\n\n:::note\nThe location listener will get unregistered once it is dropped. Make sure to store the handle inside your\ncomponent state.\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // handle event\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` and `ctx.link().route::<R>()` can also be used to retrieve the location and the route once.\n\n### Query Parameters\n\n#### Specifying query parameters when navigating\n\nIn order to specify query parameters when navigating to a new route, use either `navigator.push_with_query` or\nthe `navigator.replace_with_query` functions. It uses the `ToQuery` trait to serialize the parameters into a query string for the URL. The `ToQuery` trait is automatically implemented for `serde` so any type that implements `Serialize` can be passed. In its simplest form, this is just a `HashMap` containing string pairs. In more complex scenarios the `ToQuery` trait can be implemented manually for a custom query format.\n\n#### Obtaining query parameters for the current route\n\n`location.query` is used to obtain the query parameters. It uses the `FromQuery` trait to deserialize the parameters from the query string\nin the URL. The `FromQuery` trait is automatically implemented for `serde` so any type that implements `Deserialize` can be passed. If the URL is formatted in an custom way, a manual implementation of `FromQuery` can be used.\n\n## Nested Router\n\nNested router can be useful when the app grows larger. Consider the following router structure:\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nThe nested `SettingsRouter` handles all URLs that start with `/settings`. Additionally, it redirects URLs that are not\nmatched to the main `NotFound` route. So `/settings/gibberish` will redirect to `/404`.\n\n:::caution\n\nThough note that this is still a work in progress so the way we do this is not final\n\n:::\n\nIt can be implemented with the following code:\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### Basename\n\nIt's possible to define a basename with `yew-router`.\nA basename is a common prefix of all routes. Both the Navigator API and\n`<Switch />` component respect basename setting. All pushed routes will be\nprefixed with the basename and all switches will strip the basename before\ntrying to parse the path into a `Routable`.\n\nIf a basename prop is not supplied to the Router component, it will use\nthe href attribute of the `<base />` element in your HTML file and\nfallback to `/` if no `<base />` is present in the HTML file.\n\n## Relevant examples\n\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## API Reference\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/concepts/suspense.mdx",
    "content": "---\ntitle: 'Suspense'\ndescription: 'Suspense for data fetching'\n---\n\nSuspense is a way to suspend component rendering whilst waiting a task\nto complete and a fallback (placeholder) UI is shown in the meanwhile.\n\nIt can be used to fetch data from server, wait for tasks to be completed\nby an agent, or perform other background asynchronous task.\n\nBefore suspense, data fetching usually happens after (Fetch-on-render) or before\ncomponent rendering (Fetch-then-render).\n\n### Render-as-You-Fetch\n\nSuspense enables a new approach that allows components to initiate data request\nduring the rendering process. When a component initiates a data request,\nthe rendering process will become suspended and a fallback UI will be\nshown until the request is completed.\n\nThe recommended way to use suspense is with hooks.\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\nIn the above example, the `use_user` hook will suspend the component\nrendering while user information is loading and a `Loading...` placeholder will\nbe shown until `user` is loaded.\n\nTo define a hook that suspends a component rendering, it needs to return\na `SuspensionResult<T>`. When the component needs to be suspended, the\nhook should return a `Err(Suspension)` and users should unwrap it with\n`?` in which it will be converted into `Html`.\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### Note on implementing suspending hooks\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) returns 2 values: the suspension context itself, and a suspension handle.\nThe latter is the one responsible for signaling when to re-render the suspended components, it provides 2 interchangeable ways to do so:\n\n1. Calling its [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) method.\n2. Dropping the handle.\n\n:::danger\n\nThe suspension handle must be stored until it's time to update components, i.e. with newly received data;\notherwise, the suspended components will enter an infinite re-render loop, thus hampering performance.\nIn the example above, the suspension handle is preserved by being moved into a closure and passed into `on_load_user_complete`.\nWhen the hypothetical user will be loaded, the closure will be called, thus calling `handle.resume()` and re-rendering the components associated with the suspension context.\n\n:::\n\n# Complete Example\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // implementation omitted.\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // implementation omitted.\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### Use Suspense in Struct Components\n\nIt's not possible to suspend a struct component directly. However, you\ncan use a function component as a [Higher Order Component](../advanced-topics/struct-components/hoc)\nto achieve suspense-based data fetching.\n\nThe [suspense example in the Yew repository](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)\ndemonstrates how to use.\n\n## Relevant examples\n\n- [Suspense](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'Build a sample app'\n---\n\nOnce you have the environment ready, you can either choose to use a starter template that contains\nthe boilerplate needed for a basic Yew app or manually set up a small project.\n\n## Using a starter template\n\nInstall [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) by following their installation instructions\nthen take the following steps:\n\n### Checkout and customize project\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n### Run project\n\n```shell\ntrunk serve\n```\n\n:::note\n\nTrunk [has a bug](https://github.com/trunk-rs/trunk/issues/852) on windows when `trunk serve` command fails. To workaround the issue you can run `trunk build` before running `trunk serve`.\n\n:::\n\n## Setting up the application manually\n\n### Create Project\n\nTo get started, create a new cargo project.\n\n```bash\ncargo new yew-app\n```\n\nOpen the newly created directory.\n\n```bash\ncd yew-app\n```\n\n### Run a hello world example\n\nTo verify the Rust environment is set up, run the initial project using `cargo run`. You should see\na \"Hello World!\" message.\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### Setting up the project as a Yew web application\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\n\n#### Update Cargo.toml\n\nAdd `yew` to the list of dependencies.\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n#### Update main.rs\n\nWe need to generate a template that sets up a root Component called `App` which renders a button\nthat updates its value when clicked. Replace the contents of `src/main.rs` with the following code.\n\n:::note\nThe call to `yew::Renderer::<App>::new().render()` inside the `main` function starts your application and mounts\nit to the page's `<body>` tag. If you would like to start your application with any dynamic\nproperties, you can instead use `yew::Renderer::<App>::with_props(..).render()`.\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### Create index.html\n\nFinally, add an `index.html` file in the root directory of your app.\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## View your web application\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve\n```\n\n:::info\nAdd option '--open' to open your default browser `trunk serve --open`.\n:::\n\nTrunk will rebuild your application if you modify any of its source code files.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\n## Congratulations\n\nYou have now successfully set up your Yew development environment, and built your first web application.\n\nExperiment with this application and review the [examples](./examples.mdx) to further your learning.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'Editor Setup'\ndescription: 'Setting your code editor'\n---\n\n:::important contribute\nUsing a different editor? Feel free to add instructions for your editor of choice.\n:::\n\n## Add a template for creating components\n\n### JetBrains IDEs\n\n1. Navigate to File | Settings | Editor | Live Templates.\n2. Select Rust and click on the + icon to add a new Live Template.\n3. Give it a name and description of your preference.\n4. Paste the following snippet(s) into the Template Text section.\n5. Change the applicability on the lower right, select Rust > Item > Module\n\nFor function components, use the following template.\n\n- (Optional) Click on Edit Variable and give `tag` a reasonable default value like \"div\", with double quotes.\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\nFor struct components, you can use the following more complicated template.\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. Navigate to File > Preferences > User Snippets.\n2. Select Rust as the language.\n3. Add the following snippet in the snippet JSON file:\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## Support for the `html!` Macro\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### Rust-Yew extension\n\n> 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)\n\nRust-Yew extension is [available on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlight, renames, hover, and more.\n\nEmmet support should work out of the box, if not please fall back to editing the `settings.json` file:\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> Below configuration works with [LazyVim](https://www.lazyvim.org) configuration and lazy.vim plugin, create a file in `lua/plugins/nvim-lspconfig.lua` (or update your `lspconfig`) with:\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/getting-started/examples.mdx",
    "content": "---\ntitle: 'Examples'\n---\n\nThe Yew repository contains many [examples] (in various states of maintenance).\nWe recommend perusing them to get a feel for how to use different features of the framework.\nWe also welcome Pull Requests and issues for when they inevitably get neglected and need some ♥️\n\nFor more details including a list of examples, refer to the [README].\n\n:::tip\nMost of the examples have a live deployment that can be found at `https://examples.yew.rs/< example_name >`.\nClick the shield on their README page in their respective sub-folder to navigate to the live demo.\n:::\n\n[examples]: https://github.com/yewstack/yew/tree/master/examples\n[readme]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/getting-started/introduction.mdx",
    "content": "---\ntitle: 'Getting Started'\n---\n\nYou will need a couple of tools to compile, build, package and debug your Yew application.\nWhen getting started, we recommend using [Trunk](https://trunkrs.dev/). Trunk is a WASM web application\nbundler for Rust.\n\n## Installing Rust\n\nTo install Rust, follow the [official instructions](https://www.rust-lang.org/tools/install).\n\n:::important\nThe minimum supported Rust version (MSRV) for Yew is `1.84.0`. Older versions will not compile.\nYou can check your toolchain version using\n`rustup show` (under \"active toolchain\") or `rustc --version`. To update your\ntoolchain, run `rustup update`.\n:::\n\n## Install WebAssembly target\n\nRust can compile source codes for different \"targets\" (e.g. different processors). The compilation\ntarget for browser-based WebAssembly is called `wasm32-unknown-unknown`. The following command will\nadd the WebAssembly target to your development environment.\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Install Trunk\n\nTrunk is the recommended tool for managing deployment and packaging and is used throughout the\ndocumentation and examples.\n\n```shell\n# note that this might take a while to install because it compiles everything from scratch\n# Trunk also provides prebuilt binaries for a number of major package managers\n# See https://trunkrs.dev/#install for further details\ncargo install --locked trunk\n```\n\n### Other options\n\nThere are options other than Trunk that may be used for bundling Yew applications. You might want to try one of these options:\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (still in early development)\n\n## Next steps\n\nWith your development environment setup, you can now either proceed with reading the documentation.\nIf you like to learn by getting your hands dirty, we recommend you check out our [tutorial](../tutorial).\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew/from-0_18_0-to-0_19_0.mdx",
    "content": "---\ntitle: 'From 0.18.0 to 0.19.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n`Yew 0.19.0` has changed a lot, thus this migration will not cover ALL of the changes.\n\nInstead only the most impactful changes are mentioned and the rest should be picked up by `cargo`.\n\n## `html!` requirement for braces around most props\n\nThe syntax of the `html!` macro has been updated, such that in most cases you will need to enclose\nprops with braces.\n\n<Tabs>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,ignore {4}\nlet super_age = 1;\nhtml!{\n    <JapaneseYew\n        age=super_age // ! Will throw an error\n    >\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Valid\" label=\"Valid\">\n\n```rust ,ignore {4}\nlet super_age = 1;\nhtml!{\n    <JapaneseYew\n        age={super_age} // Correct\n    >\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Shorthand\" label=\"Shorthand\">\n\nShorthand initialization has been added:\n\n```rust ,ignore {4}\nlet age = 1;\nhtml!{\n    <JapaneseYew\n        {age}\n    >\n}\n```\n\n  </TabItem>\n</Tabs>\n\nThere is a community provided regex to help automate the update, though we can't promise it will work\nall the time.\n\nIt breaks when it encounters closures (specifically the `|_|` syntax).\n\nfind with `=(?![{\">=\\s])([^\\s></]*(\\s!{0,1}[=|&]{2}\\s[^\\s></]*)*)`\n\nreplace with `={$1}`\n\n## Function components\n\n[Function components](concepts/function-components/introduction.mdx) are a brand new way to write components that\nrequires less boilerplate than their structural counterpart.\n\nWhile this change does not force you to change your codebase, as you migrate from `0.18` to `0.19`, this migration time might present a good opportunity to start using them in your codebase.\n\n## Struct components lifecycle methods and ctx\n\n[Struct components](advanced-topics/struct-components/introduction.mdx) also received changes to their API.\n\n### ShouldRender removed in favor of bool\n\n`ShouldRender` removed in favor of `bool` and can be just find all - replaced throughout your code base.\n\n### ctx, props, link\n\nStruct components no longer own props and link, instead they receive `ctx: &Context<Self>` argument in lifetime methods that can later give you access to `ctx.props() -> &Properties` and `ctx.link() -> &Scope<Self>`.\n\nYou will need to remove `link` and `props` from your component struct fields as such all lifetime methods got updated.\n\n### Lifetime methods in Component trait\n\nFor new API look in the [Component trait](https://github.com/yewstack/yew/blob/9b6bc96826d53ec38aa3ecc02e3a1e132692c411/packages/yew/src/html/component/mod.rs#L37-L97)\n\n## `web-sys` is no longer re-exported\n\nAdd `web-sys` as your project dependency and one by one add the needed features like `Event` or `Window`.\n\n## Services\n\nDuring this update all services were removed in favor of community driven solutions like [gloo](https://github.com/rustwasm/gloo)\n\nRemove this entirely. `yew-services` adds a layer a abstraction which makes it easier to call external resources. This is all well and good but this layer is supposed to be specific to Yew. It would be better if an framework agnostic abstraction existed instead.\n\n- `ConsoleService`\n  Use [gloo-console](https://crates.io/crates/gloo-console) or [`weblog`](https://crates.io/crates/weblog) instead.\n- `DialogService`\n  Use [`gloo-dialogs`](https://docs.rs/gloo-dialogs/) instead.\n- `IntervalService`\n  Use [`gloo-timers`](https://docs.rs/gloo-timers/) instead.\n- `KeyboardService`\n  `on*` event handlers in yew already handle it. Using this service is even more cumbersome because it requires use of `NodeRef` in order to call any functions provided by it.\n\n```rust ,ignore\nlet onkeydown = Callback::from(|e| {\n    e.prevent_default();\n    todo!(\"use `e`, just like in service methods.\");\n});\nhtml! {\n    <input {onkeydown} />\n}\n```\n\n- `ResizeService`\n  Use [`gloo-events`](https://docs.rs/gloo-events) to attach the listener instead.\n- `StorageService`\n  Use [`gloo-storage`](https://docs.rs/gloo-storage/) instead.\n- `TimeoutService`\n  Use [`gloo-timers`](https://docs.rs/gloo-timers/) instead.\n- `WebSocketService`\n  Use [`wasm-sockets`](https://github.com/scratchyone/wasm-sockets) or [`gloo-net`](https://crates.io/crates/gloo-net) instead.\n- `FetchService`\n  Use [`reqwest`](https://crates.io/crates/reqwest) or [`gloo-net`](https://crates.io/crates/gloo-net) instead.\n\n## New crate - yew-agent\n\nYew agents were removed to a separate crate, see [yew agents migration guide](./../yew-agent/from-0_0_0-to-0_1_0)\n\n## Ending note\n\nWe are sorry if some things are not covered in this guide as it was truly a huge update and we hope\nthat the uncovered issues will be clearly explained in error messages emitted by the Rust compiler.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\n## `_as_body` variant of `start_app` is removed\n\nThis method of controlling body has caused issues in event registration and\nSSR hydration. They have been removed. Read more in the [github issue](https://github.com/yewstack/yew/pull/2346).\n\n## New Hooks and Function Components API\n\nThe Function Components and Hooks API are re-implemented with a different mechanism:\n\n- User-defined hooks are now required to have a prefix `use_` and must be marked with the `#[hook]` attribute.\n- Hooks will now report compile errors if they are not called from the top level of a function component\n  or a user defined hook. The limitation existed in the previous version of Yew as well. In this version,\n  It is reported as a compile time error.\n\n## Automatic Message Batching\n\nThe scheduler now schedules its start to the end of the browser event loop.\nAll messages queued during in the meantime will be run in batch.\nThe running order of messages between components are no longer guaranteed, but\nmessages sent to the same component is still acknowledged in an FIFO order.\nIf multiple updates will result in a render, the component will be rendered\nonce.\n\n:::info What this means to developers?\n\nFor struct components, this means that if you send 2 messages to 2 different\ncomponents, they will not be guaranteed to be seen in the same order they are\nsent. If you send 2 messages to the same component, they will still be passed\nto the component in the order they are sent. The messages are not sent to the\ncomponent immediately so you should not assume that when the component receives\na message it still has the same state at the time the message is created.\n\nFor function components, if you store states with `use_state(_eq)`\nand the new value of that state depends on the previous value,\nyou may want to switch to `use_reducer(_eq)`. The new value of the state will\nnot be visible / acknowledged until the next time the component is rendered.\nThe reducer action works similar to messages for struct components and\nwill be sent to the reducer function in the same order as they are dispatched.\nThe reducer function can see all previous changes at the time they are run.\n\n:::\n\n## Yew Renderer\n\n`start_app*` has been replaced by `yew::Renderer`.\n\nYou need to enable feature `csr` to use `yew::Renderer`.\n\n## `ref` prop for Components\n\nComponents no longer have a `ref` prop. Trying to add a node ref to a component\nwill result in a compile error\n\nPreviously node ref passed to a component was bound to the first element rendered by it.\nIf this behavior is still desired, it is recommended to use add a `r#ref` field to the\ncomponent's properties and bind it manually\n\n## `changed` Method on Components\n\nThe method `fn changed()` has now a new argument to provide the old properties\nto the function.\n\nThe old method's signature was:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>) -> bool\n```\n\nThe new method's signature is now:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool\n```\n\nThis can be adjusted automatically in your code using this bash script (save\nyour code before running this!):\n\n```bash\nperl -p -i -e  's/fn changed\\(&mut self, (\\w+): &Context<Self>\\)/fn changed(&mut self, $1: &Context<Self>, _old_props: &Self::Properties)/g' $(find . -name \\*.rs)\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew/from-0_20_0-to-0_21_0.mdx",
    "content": "---\ntitle: 'From 0.20.0 to 0.21.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Dependencies as first hook argument and `use_effect_with`\n\n- Replace `use_effect_with_deps` with new `use_effect_with`\n- `use_effect_with`, `use_callback`, `use_memo` now take dependencies as their first argument\n\n### Automated refactor\n\nWith the help of [https://ast-grep.github.io](https://ast-grep.github.io/guide/quick-start.html)\nHere are commands that can do the refactoring for you.\n\n```bash\nsg --pattern 'use_effect_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_effect_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_callback($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_callback($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_callback($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_callback($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_memo($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_memo($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_future_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_future_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n```\n\n### Reasoning\n\nThis will enable more ergonomic use of hooks, consider:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\n{\n    let id = some_dep.id(); // Have to extract it in advance, some_dep is moved already in the second argument\n    use_effect_with_dep(move |_| { todo!(); drop(some_dep); }, id);\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\nuse_effect_with(some_dep.id(), move |_| { todo!(); drop(some_dep); });\n\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew/from-0_21_0-to-0_22_0.mdx",
    "content": "---\ntitle: 'From 0.21.0 to 0.22.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## MSRV raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. Update your toolchain:\n\n```bash\nrustup update stable\n```\n\n## `#[function_component]` renamed to `#[component]`\n\nThe `#[function_component]` attribute has been renamed to `#[component]` for brevity. The old name is deprecated but still works.\n\n### Automated refactor\n\n```bash\n# Using sed (simple but also replaces in comments/strings)\nfind . -name \"*.rs\" -exec sed -i 's/#\\[function_component\\]/#[component]/g' {} +\nfind . -name \"*.rs\" -exec sed -i 's/#\\[function_component(/#[component(/g' {} +\n\n# Or using ast-grep (recommended - AST-aware, preserves comments/strings)\n# Important: Run the named pattern FIRST to preserve component names\nast-grep run -p '#[function_component($$$ARGS)]' -r '#[component($$$ARGS)]' -l rust --update-all .\nast-grep run -p '#[function_component]' -r '#[component]' -l rust --update-all .\n```\n\n:::note\nThe sed commands will also replace occurrences in comments and strings. Use ast-grep for more precise refactoring.\n:::\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\n#[function_component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello\"}</div> }\n}\n\n#[function_component(Named)]\nfn AnotherComponent() -> Html {\n    html! { <div>{\"World\"}</div> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\n#[component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello\"}</div> }\n}\n\n#[component(Named)]\nfn AnotherComponent() -> Html {\n    html! { <div>{\"World\"}</div> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `class=(...)` syntax removed\n\nThe deprecated `class=(expr)` syntax has been removed. Use `class={classes!(...)}` instead.\n\n### Finding occurrences\n\n```bash\n# Find all files using the old class=(...) syntax\ngrep -rn \"class=(\" --include=\"*.rs\" .\n```\n\n### Manual refactor\n\nThe transformation is straightforward: wrap the tuple contents with `classes!()` and change parentheses to braces:\n\n- `class=(a, b)` → `class={classes!(a, b)}`\n- `class=(expr)` → `class={classes!(expr)}`\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nhtml! {\n    <div class=(some_class, other_class)>{\"Content\"}</div>\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nhtml! {\n    <div class={classes!(some_class, other_class)}>{\"Content\"}</div>\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `ToHtml` trait removed\n\nThe `ToHtml` trait has been removed. Use `IntoPropValue` for custom type conversions.\n\n## For-loops in `html!` macro\n\nYou can now use for-loops directly in the `html!` macro. This is optional but provides cleaner syntax:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before (still works)\" default>\n\n```rust ,ignore\nhtml! {\n    <ul>\n        { for items.iter().map(|item| html! { <li key={item.id}>{ &item.name }</li> }) }\n    </ul>\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After (new syntax)\">\n\n```rust ,ignore\nhtml! {\n    <ul>\n        for item in items {\n            <li key={item.id}>{ &item.name }</li>\n        }\n    </ul>\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `use_effect_with` no longer requires `|| ()` return\n\nEffect hooks no longer require returning `|| ()` when there's no cleanup:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nuse_effect_with(deps, |deps| {\n    // do something\n    || ()  // had to return this\n});\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nuse_effect_with(deps, |deps| {\n    // do something\n    // no return needed!\n});\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew-agent/from-0_0_0-to-0_1_0.mdx",
    "content": "---\ntitle: 'From 0.0.0 to 0.1.0'\n---\n\nThis is the first release of `yew-agents` being separated from `yew`\n\nThe only thing you will need to do is change the import paths from `yew::*` to `yew_agents::*`\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew-agent/from-0_1_0-to-0_2_0.mdx",
    "content": "---\ntitle: 'From 0.1.0 to 0.2.0'\n---\n\n## Removal of `Context` and `Job` Agents\n\nThe `Context` and `Job` Agents have been removed in favour of Yew's Context API.\n\nYou can see the updated [`pub_sub`](https://github.com/yewstack/yew/tree/master/examples/pub_sub)\nwhich demonstrate how to use the context API.\n\nFor users of `yew_agent::utils::store`, you may switch to third party solutions like: [Yewdux](https://github.com/intendednull/yewdux) or [Bounce](https://github.com/futursolo/bounce).\n\n## `Threaded` has been separated into `PublicAgent` and `PrivateAgent`\n\nReplace `use yew_agent::Threaded;` with `use yew_agent::PublicAgent;`.\n\n:::note\n\n`Threaded` was never implemented for Private Agents.\nAll existing web worker-based agents are Public Agents.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew-agent/from-0_3_0-to-0_4_0.mdx",
    "content": "---\ntitle: 'From 0.3.0 to 0.4.0'\n---\n\n## MSRV raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. Update your toolchain:\n\n```bash\nrustup update stable\n```\n\n## gloo-worker vendored\n\nThe external dependency on `gloo-worker` has been removed. All worker functionality is now built into `yew-agent`.\n\n### Update imports\n\nIf you were importing types from `gloo-worker`, update to import from `yew_agent`:\n\n```rust ,ignore\n// Before\nuse gloo_worker::{Spawnable, Worker, WorkerScope};\n\n// After\nuse yew_agent::prelude::*;\n// or\nuse yew_agent::{Spawnable, Worker, WorkerScope};\n```\n\n### Codec trait\n\nThe `Codec` trait is now defined in `yew-agent`:\n\n```rust ,ignore\n// Before\nuse gloo_worker::Codec;\n\n// After\nuse yew_agent::Codec;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew-router/from-0_15_0-to-0_16_0.mdx",
    "content": "---\ntitle: 'From 0.15.0 to 0.16.0'\n---\n\nThe router API has been completely rewritten in `0.16.0`.\n\nBecause it is such a radical change, there are too many things to list out here, so we highly\nrecommend to read the updated [router documentation](./../../concepts/router) and adapt your app\naccordingly.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/migration-guides/yew-router/from-0_16_0-to-0_17_0.mdx",
    "content": "---\ntitle: 'From 0.16.0 to 0.17.0'\n---\n\n## `Switch::render` is no longer needed\n\nThe `<Switch />` component now accepts a closure of `Fn(Routable) -> Html` as\nthe render function directly.\n\n## `navigator` API\n\nThe History API has been replaced with the Navigator API.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nA proposal for integrated CSS support can be found here:\n[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)\n\nThis contains a lot of discussion about how to best integrate CSS support into Yew.\n\nCurrently, the approach we have adopted is to encourage developers to build many systems, before\nadopting the most popular one.\n\nThe community is currently developing several projects to make it easy to add styles to\nprojects. A few are given below:\n\n#### Component Libraries\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - A styling framework for Yew without any JavaScript dependencies.\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design Components.\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS Components.\n- [Yewtify](https://github.com/yewstack/yewtify) – Implements the features provided by the Vuetify framework in Yew.\n\n#### Styling Solutions\n\n- [stylist](https://github.com/futursolo/stylist-rs) - A CSS-in-Rust styling solution for WebAssembly Applications.\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind Utility Classes.\n\n:::important contribute\nIf you're developing a project adding styles to Yew please submit a PR adding yourself to this list!\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/more/debugging.mdx",
    "content": "---\ntitle: 'Debugging'\n---\n\n## Panics\n\nYew automatically logs panics in the browser console.\n\n## Console Logging\n\nIn JavaScript, `console.log()` is used to log to the browser console. Some options for Yew are listed below.\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate integrates with [`log`](https://crates.io/crates/log) crate to send the log level, source line, and filename to the browser console.\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nThis crate is part of Gloo, a collection of libraries providing ergonomic Rust wrappers for browser APIs.\nThe `log!` macro can take a `JsValue` directly which is slightly easier to use than `wasm_logger`.\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` can be used with [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) to output messages to the browser console.\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## Debugging component lifecycles\n\n[`tracing`](https://crates.io/crates/tracing) can be used to collect event information related to a component's lifecycle. `tracing` also comes with a feature flag for `log` support, which integrates nicely with `wasm-logger`.\n\n[Compile time filters](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) can be used to adjust verbosity or disable logging, which should result in a smaller Wasm file.\n\n## Source Maps\n\nThere is [some support](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) for source maps.\nHowever, some configuration is required.\n\n## Past Articles\n\nSome past articles on the state of debugging in WebAssembly in Rust can be found below. They may serve as interesting reads.\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) does not support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/more/deployment.mdx",
    "content": "---\ntitle: 'Deployment'\ndescription: 'Deploying Yew applications'\n---\n\nWhen you are ready to deploy your Yew application to a server, you have various options for deployment.\n\n`trunk build --release` builds your app in release mode. Set up your HTTP server so that it serves `index.html` whenever your site is visited, and requests to static paths like `index_<hash>.js` and `index_bg_<hash>.wasm` are served with the contents of their respective contents from the dist directory generated by trunk.\n\n:::important A note about `trunk serve --release`\nDo **not** use `trunk serve --release` to serve your application in production.\nIt should only be used for testing the release build during development\n:::\n\n## Server configuration\n\n### Serving `index.html` as a fallback\n\nIf the application uses the [Yew router](concepts/router.mdx), you must configure the server to return the `index.html` when asked for a file that it does not have.\n\nAn application with Yew router is built as a [Single Page Application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA). When the user navigates to a URL from within a running client, the router interprets the URL and routes to that page.\n\nBut on a fresh load, such as when navigating to the page by entering it in the address bar or refreshing the page, all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router. A wrongly configured server would return with the status 404 - Not Found.\n\nBy returning `index.html` instead, the app loads as it normally would, as if the request was for `/` until the router notices that the route is `/show/42` and displays the appropriate contents.\n\n### Configuring correct MIME-type for Web Assembly asset.\n\nThe WASM files must be served with the [Content-Type header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) set to `application/wasm` MIME-type.\n\nMost servers and hosting services already do this by default. If yours does not, consult its documentation. An incorrect MIME type will, in most web browsers, result in an error similar to the following:\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## Building for Relative Paths\n\nBy default, trunk will assume that your site is being served at `/` and build the site accordingly. This behavior can be overridden by adding `<base data-trunk-public-url />` to the `index.html` file. Trunk rewrites this tag to contain the value passed to `--public-url`. Yew router automatically detects the presence of `<base />` and handles it appropriately.\n\n## Customizing behavior using environment variables\n\nIt is common to customize the build environment by using environment variables. Since the app is run in a browser, we cannot read the environment variables at runtime.\nThe [`std::env!`](https://doc.rust-lang.org/std/macro.env.html) macro can be used to obtain a value of an environment variable at compile time.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/more/roadmap.mdx",
    "content": "---\ntitle: 'Roadmap'\ndescription: 'The planned feature roadmap for the Yew framework'\n---\n\n## Prioritization\n\nThe prioritization of upcoming features and focuses of the framework is determined by the community.\nIn Spring 2020, a developer survey was sent out to collect feedback on the direction of the project.\nYou can find the summary in the [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D).\n\n:::note\nStatus of all major initiatives can be tracked on the Yew Github [project board](https://github.com/yewstack/yew/projects)\n:::\n\n## Focuses\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Most requested features\n\n1. [Functional Components](https://github.com/yewstack/yew/projects/3)\n2. [Component Library](https://github.com/yewstack/yew/projects/4)\n3. Better state management\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n### Issues needed for production readiness\n\n- Improve Yew test coverage\n- Reduce binary size\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- Create tutorial\n- Simplify project setup\n\n### Pain points\n\n- [Component boilerplate](https://github.com/yewstack/yew/issues/830)\n- [Agents](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/more/testing.mdx",
    "content": "---\ntitle: 'Testing apps'\ndescription: 'Testing your app'\n---\n\n:::info\nWe are working on making it easy to test components, but this is currently a work in progress.\n\nSupport for [shallow rendering](https://github.com/yewstack/yew/issues/1413) can be found in the GitHub repository.\n:::\n\n## Snapshot testing\n\nYew exposes the `yew::tests::layout_tests` module to facilitate snapshot testing of components.\n\n:::important contribute\nHelp improve the documentation for snapshot testing.\n:::\n\n## wasm_bindgen_test\n\nThe Rust/WASM working group maintains a crate called [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nwhich allows you to run tests in a browser in a similar fashion to how the built-in `#[test]` procedural macro works.\nMore information is given in the [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nfor this module.\n"
  },
  {
    "path": "website/versioned_docs/version-0.22/tutorial/index.mdx",
    "content": "---\ntitle: 'Tutorial'\nslug: /tutorial\n---\n\n## Introduction\n\nIn this hands-on tutorial, we will take a look at how we can use Yew to build web applications.\n**Yew** is a modern [Rust](https://www.rust-lang.org/) framework for building front-end web apps using [WebAssembly](https://webassembly.org/).\nYew encourages a reusable, maintainable, and well-structured architecture by leveraging Rust's powerful type system.\nA large ecosystem of community-created libraries, known in Rust as [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html),\nprovide components for commonly-used patterns such as state management.\n[Cargo](https://doc.rust-lang.org/cargo/), the package manager for Rust, allows us to take advantage of the\nnumerous crates available on [crates.io](https://crates.io), such as Yew.\n\n### What we are going to build\n\nRustconf is an intergalactic gathering of the Rust community that happens annually.\nRustconf 2020 had a plethora of talks that provided a good amount of information.\nIn this hands-on tutorial, we will be building a web application to help fellow Rustaceans\nget an overview of the talks and watch them all from one page.\n\n## Setting up\n\n### Prerequisites\n\nThis tutorial assumes you are already familiar with Rust. If you are new to Rust,\nthe free [Rust Book](https://doc.rust-lang.org/book/ch00-00-introduction.html) offers a great starting point for\nbeginners and continues to be an excellent resource even for experienced Rust developers.\n\nEnsure the latest version of Rust is installed by running `rustup update` or by\n[installing rust](https://www.rust-lang.org/tools/install) if you have not already done so.\n\nAfter installing Rust, you can use Cargo to install `trunk` by running:\n\n```bash\ncargo install trunk\n```\n\nWe will also need to add the WASM build target by running:\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### Setting up the project\n\nFirst, create a new cargo project:\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nTo verify the Rust environment is set up properly, run the initial project using the cargo build tool.\nAfter the output about the build process, you should see the expected \"Hello, world!\" message.\n\n```bash\ncargo run\n```\n\n## Our first static page\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\nUpdate the files as follows:\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.22\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nNow, let's create an `index.html` at the root of the project.\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### Start the development server\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve --open\n```\n\n:::info\nRemove option '--open' to not open your default browser `trunk serve`.\n:::\n\nTrunk will open your application in your default browser, watch the project directory and helpfully rebuild your\napplication if you modify any source files.\nThis will fail if the socket is being used by another application.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\nIf you are curious, you can run `trunk help` and `trunk help <subcommand>` for more details on what is happening.\n\n### Congratulations\n\nYou have now successfully set up your Yew development environment and built your first Yew web application.\n\n## Building HTML\n\nYew makes use of Rust's procedural macros and provides us with a syntax similar to JSX (an extension to JavaScript\nwhich allows you to write HTML-like code inside JavaScript) to create the markup.\n\n### Converting classic HTML\n\nSince we already have a pretty good idea of what our website will look like, we can simply translate our mental draft\ninto a representation compatible with `html!`. If you are comfortable writing simple HTML, you should have no problem\nwriting marking inside `html!`. It is important to note that the macro does differ from HTML in a few ways:\n\n1. Expressions must be wrapped in curly braces (`{ }`)\n2. There must only be one root node. If you want to have multiple elements without wrapping them in a container,\n   an empty tag/fragment (`<> ... </>`) is used\n3. Elements must be closed properly.\n\nWe want to build a layout that looks something like this in raw HTML:\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nNow, let's convert this HTML into `html!`. Type (or copy/paste) the following snippet into the body of `app` function\nsuch that the value of `html!` is returned by the function\n\n```rust {3-21}\n#[component]\nfn App() -> Html {\n-   html! {\n-       <h1>{ \"Hello World\" }</h1>\n-   }\n+   html! {\n+       <>\n+           <h1>{ \"RustConf Explorer\" }</h1>\n+           <div>\n+               <h3>{ \"Videos to watch\" }</h3>\n+               <p>{ \"John Doe: Building and breaking things\" }</p>\n+               <p>{ \"Jane Smith: The development process\" }</p>\n+               <p>{ \"Matt Miller: The Web 7.0\" }</p>\n+               <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           </div>\n+           <div>\n+               <h3>{ \"John Doe: Building and breaking things\" }</h3>\n+               <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n+           </div>\n+       </>\n+   }\n}\n```\n\nRefresh the browser page, and you should see the following output displayed:\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### Using Rust language constructs in the markup\n\nA big advantage of writing markup in Rust is that we get all the coolness of Rust in our markup.\nNow, instead of hardcoding the list of videos in the HTML, let's define them as a `Vec` of `Video` structs.\nWe create a simple `struct` (in `main.rs` or any file of our choice) that will hold our data.\n\n```rust\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: AttrValue,\n    speaker: AttrValue,\n    url: AttrValue,\n}\n```\n\nNext, we will create instances of this struct in our `app` function and use those instead of hardcoding the data:\n\n```rust {3-29}\n#[component]\nfn App() -> Html {\n+   let videos = vec![\n+       Video {\n+           id: 1,\n+           title: \"Building and breaking things\".into(),\n+           speaker: \"John Doe\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 2,\n+           title: \"The development process\".into(),\n+           speaker: \"Jane Smith\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 3,\n+           title: \"The Web 7.0\".into(),\n+           speaker: \"Matt Miller\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 4,\n+           title: \"Mouseless development\".into(),\n+           speaker: \"Tom Jerry\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+   ];\n+\n```\n\nTo display them, we can use a `for` loop right in the macro in place of the hardcoded HTML:\n\n```rust {6-12}\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <p>{ \"John Doe: Building and breaking things\" }</p>\n-               <p>{ \"Jane Smith: The development process\" }</p>\n-               <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-               <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+               for video in &videos {\n+                   <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+               }\n            </div>\n            // ...\n        </>\n    }\n```\n\n:::tip\nKeys on list items help Yew keep track of which items have changed in the list, resulting in faster re-renders.\n[It is always recommended to use keys in lists](/concepts/html/lists.mdx#keyed-lists).\n:::\n\n## Components\n\nComponents are the building blocks of Yew applications. By combining components, which can be made of other components,\nwe build our application. By structuring our components for re-usability and keeping them generic, we will be able to use\nthem in multiple parts of our application without having to duplicate code or logic.\n\nThe `app` function we have been using so far is a component, called `App`. It is a \"function component\".\nThere are two different types of components in Yew.\n\n1. Struct Components\n2. Function Components\n\nIn this tutorial, we will be using function components.\n\nNow, let's split up our `App` component into smaller components. We begin by extracting the videos list into\nits own component.\n\n```rust\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component]\nfn VideosList(VideosListProps { videos }: &VideosListProps) -> Html {\n    html! {\n        for video in videos {\n            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }\n}\n```\n\nNotice the parameters of our `VideosList` function component. A function component takes only one argument which\ndefines its \"props\" (short for \"properties\"). Props are used to pass data down from a parent component to a child component.\nIn this case, `VideosListProps` is a struct that defines the props.\n\n:::important\nThe struct used for props must implement `Properties` by deriving it.\n:::\n\nNow, we can update our `App` component to make use of `VideosList` component.\n\n```rust {9-12}\n#[component]\nfn App() -> Html {\n    // ...\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               for video in &videos {\n-                   <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-               }\n+               <VideosList {videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nBy looking at the browser window, we can verify that the lists are rendered as they should be.\nWe have moved the rendering logic of lists to its component. This shortens the `App` component’s source code,\nmaking it easier for us to read and understand.\n\n### Making it interactive\n\nThe final goal here is to display the selected video. To do that, `VideosList` component needs to \"notify\" its\nparent when a video is selected, which is done via a `Callback`. This concept is called \"passing handlers\".\nWe modify its props to take an `on_click` callback:\n\n```rust {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+   on_click: Callback<Video>,\n}\n```\n\nThen we modify the `VideosList` component to \"emit\" the selected video to the callback.\n\n```rust {2-18}\n#[component]\n-fn VideosList(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn VideosList(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+   let on_select = |video: &Video| {\n+       let on_click = on_click.clone();\n+       let video = video.clone();\n+       Callback::from(move |_| {\n+           on_click.emit(video.clone())\n+       })\n+   };\n+\n    html! {\n        for video in videos {\n-           <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+           <p key={video.id} onclick={on_select(video)}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }\n}\n```\n\nNext, we need to modify the usage of `VideosList` to pass that callback. But before doing that, we should create\na new component, `VideoDetails`, that is displayed when a video is clicked.\n\n```rust\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component]\nfn VideoDetails(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ &*video.title }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\nNow, modify the `App` component to display `VideoDetails` component whenever a video is selected.\n\n```rust {3-11,18-19,21-28}\n        },\n    ];\n+\n+   let selected_video = use_state(|| None);\n+\n+   let on_video_select = {\n+       let selected_video = selected_video.clone();\n+       Callback::from(move |video: Video| {\n+           selected_video.set(Some(video))\n+       })\n+   };\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <VideosList {videos} />\n+               <VideosList {videos} on_click={on_video_select} />\n            </div>\n+           if let Some(video) = &*selected_video {\n+               <VideoDetails video={video.clone()} />\n+           }\n-           <div>\n-               <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-               <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-           </div>\n        </>\n    }\n}\n```\n\n### Handling state\n\nRemember the `use_state` used earlier? That is a special function, called a \"hook\". Hooks are used to \"hook\" into\nthe lifecycle of a function component and perform actions. You can learn more about this hook, and others\n[here](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks).\n\n:::note\nStruct components act differently. See [the documentation](advanced-topics/struct-components/introduction.mdx) to learn about those.\n:::\n\n## Fetching data (using external REST API)\n\nIn a real-world application, data will usually come from an API instead of being hardcoded. Let's fetch our\nvideos list from an external source. For this we will need to add the following crates:\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  For making the fetch call.\n- [`serde`](https://serde.rs) with derive features\n  For de-serializing the JSON response\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  For executing Rust Future as a Promise\n\nLet's update the dependencies in `Cargo.toml` file:\n\n```toml title=\"Cargo.toml\" {2-6}\n[dependencies]\n-yew = { version = \"0.22\", features = [\"csr\"] }\n+yew = { version = \"0.22\", features = [\"csr\", \"serde\"] }\n+gloo-net = \"0.6\"\n+serde = { version = \"1.0\", features = [\"derive\"] }\n+wasm-bindgen-futures = \"0.4\"\n```\n\nYew's `serde` feature enables integration with the `serde` crate, the important point for us is that\nit adds a `serde::Deserialize` impl to `AttrValue`.\n\n:::note\nWhen choosing dependencies make sure they are `wasm32` compatible!\nOtherwise you won't be able to run your application.\n:::\n\nUpdate the `Video` struct to derive the `Deserialize` trait:\n\n```rust {2,4-5}\nuse yew::prelude::*;\n+use serde::Deserialize;\n// ...\n-#[derive(Clone, PartialEq)]\n+#[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: AttrValue,\n    speaker: AttrValue,\n    url: AttrValue,\n}\n```\n\nNow as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data\n\n```rust {2,6-50,59-60}\nuse yew::prelude::*;\n+use gloo_net::http::Request;\n\n#[component]\nfn App() -> Html {\n-   let videos = vec![\n-       Video {\n-           id: 1,\n-           title: \"Building and breaking things\".into(),\n-           speaker: \"John Doe\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 2,\n-           title: \"The development process\".into(),\n-           speaker: \"Jane Smith\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 3,\n-           title: \"The Web 7.0\".into(),\n-           speaker: \"Matt Miller\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 4,\n-           title: \"Mouseless development\".into(),\n-           speaker: \"Tom Jerry\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-   ];\n-\n+   let videos = use_state(|| vec![]);\n+   {\n+       let videos = videos.clone();\n+       use_effect_with((), move |_| {\n+           let videos = videos.clone();\n+           wasm_bindgen_futures::spawn_local(async move {\n+               let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                   .send()\n+                   .await\n+                   .unwrap()\n+                   .json()\n+                   .await\n+                   .unwrap();\n+               videos.set(fetched_videos);\n+           });\n+           || ()\n+       });\n+   }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <VideosList {videos} on_click={on_video_select} />\n+               <VideosList videos={(*videos).clone()} on_click={on_video_select} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n:::note\nWe are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have\n[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).\n:::\n\nNow, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.\nTo fix that, we need a proxy server. Luckily trunk provides that.\n\nUpdate the following line:\n\n```rust {2-3}\n-               let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+               let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n```\n\nNow, rerun the server with the following command:\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nRefresh the tab and everything should work as expected.\n\n## Wrapping up\n\nCongratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.\n\n## What's next\n\nThis application is very far from perfect or useful. After going through this tutorial,\nyou can use it as a jumping-off point to explore more advanced topics.\n\n### Styles\n\nOur apps look very ugly. There is no CSS or any kind of style.\nUnfortunately, Yew does not offer a built-in way to style components. See [Trunk's assets](https://trunkrs.dev/assets/)\nto learn how to add style sheets.\n\n### More libraries\n\nOur app made use of only a few external dependencies. There are lots of crates out there that can be used.\nSee [external libraries](/community/external-libs) for more details.\n\n### Learning more about Yew\n\nRead our [official documentation](../getting-started/introduction.mdx). It explains a lot of concepts in much more detail.\nTo learn more about the Yew API, see our [API docs](https://docs.rs/yew).\n\n<!-- COMBINE CODE BLOCKS -->\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n:::caution\n\nInspecting and manipulating `Children` can often result in surprising and hard-to-explain behaviours in your application.\nThis can lead to edge cases and often does not yield expected result.\nYou should consider other approaches if you are trying to manipulate `Children`.\n\nYew supports using `Html` as the type of the children prop.\nYou should use `Html` as children if you do not need `Children` or `ChildrenRenderer`.\nIt doesn't have the drawbacks of `Children` and has a lower performance overhead.\n\n:::\n\n## General usage\n\n_Most of the time,_ when allowing a component to have children, you don't care\nwhat type of children the component has. In such cases, the below example will\nsuffice.\n\n```rust\nuse yew::{html, Component, Context, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                {ctx.props().children.clone()}\n            </div>\n        }\n    }\n}\n```\n\n## Advanced usage\n\n### Typed children\n\nIn cases where you want one type of component to be passed as children to your component,\nyou can use `yew::html::ChildrenWithProps<T>`.\n\n```rust\nuse yew::{html, ChildrenWithProps, Component, Context, Html, Properties};\n\npub struct Item;\n\nimpl Component for Item {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"item\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenWithProps<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n## Nested Children with Props\n\nNested component properties can be accessed and mutated if the containing component types its children.\n\n```rust\nuse std::rc::Rc;\nuse yew::prelude::*;\n\n#[derive(Clone, PartialEq, Properties)]\npub struct ListItemProps {\n    value: String,\n}\n\n#[component]\nfn ListItem(props: &ListItemProps) -> Html {\n    let ListItemProps { value } = props.clone();\n    html! {\n        <span>\n            {value}\n        </span>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct Props {\n    pub children: ChildrenWithProps<ListItem>,\n}\n\n#[component]\nfn List(props: &Props) -> Html {\n    let modified_children = props.children.iter().map(|mut item| {\n            let mut props = Rc::make_mut(&mut item.props);\n            props.value = format!(\"item-{}\", props.value);\n            item\n    });\n    html! {{for modified_children}}\n}\n\nhtml! {\n    <List>\n        <ListItem value=\"a\" />\n        <ListItem value=\"b\" />\n        <ListItem value=\"c\" />\n    </List>\n};\n```\n\n### Enum typed children\n\nOf course, sometimes you might need to restrict the children to a few different\ncomponents. In these cases, you have to get a little more hands-on with Yew.\n\nThe [`derive_more`](https://github.com/JelteF/derive_more) crate is used here\nfor better ergonomics. If you don't want to use it, you can manually implement\n`From` for each variant.\n\n```rust\nuse yew::{\n    html, html::ChildrenRenderer, virtual_dom::VChild, Component,\n    Context, Html, Properties,\n};\n\npub struct Primary;\n\nimpl Component for Primary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Primary\" }\n        }\n    }\n}\n\npub struct Secondary;\n\nimpl Component for Secondary {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"Secondary\" }\n        }\n    }\n}\n\n#[derive(Clone, derive_more::From, PartialEq)]\npub enum Item {\n    Primary(VChild<Primary>),\n    Secondary(VChild<Secondary>),\n}\n\n// Now, we implement `Into<Html>` so that yew knows how to render `Item`.\n#[allow(clippy::from_over_into)]\nimpl Into<Html> for Item {\n    fn into(self) -> Html {\n        match self {\n            Self::Primary(child) => child.into(),\n            Self::Secondary(child) => child.into(),\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct ListProps {\n    #[prop_or_default]\n    pub children: ChildrenRenderer<Item>,\n}\n\npub struct List;\n\nimpl Component for List {\n    type Message = ();\n    type Properties = ListProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"list\">\n                { for ctx.props().children.iter() }\n            </div>\n        }\n    }\n}\n```\n\n### Optional typed child\n\nYou can also have a single optional child component of a specific type too:\n\n```rust\nuse yew::{\n    html, html_nested, virtual_dom::VChild, Component,\n    Context, Html, Properties\n};\n\npub struct PageSideBar;\n\nimpl Component for PageSideBar {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            { \"sidebar\" }\n        }\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct PageProps {\n    #[prop_or_default]\n    pub sidebar: Option<VChild<PageSideBar>>,\n}\n\nstruct Page;\n\nimpl Component for Page {\n    type Message = ();\n    type Properties = PageProps;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <div class=\"page\">\n                { ctx.props().sidebar.clone() }\n                // ... page content\n            </div>\n        }\n    }\n}\n\n// The page component can be called either with the sidebar or without:\n\npub fn render_page(with_sidebar: bool) -> Html {\n    if with_sidebar {\n        // Page with sidebar\n        html! {\n            <Page sidebar={html_nested! {\n                <PageSideBar />\n            }} />\n        }\n    } else {\n        // Page without sidebar\n        html! {\n            <Page />\n        }\n    }\n}\n```\n\n## Further Reading\n\n- For a real-world example of this pattern, check out the yew-router source code. For a more advanced example, check out the [nested-list example](https://github.com/yewstack/yew/tree/master/examples/nested_list) in the main yew repository.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/how-it-works.mdx",
    "content": "---\ntitle: 'How it works'\ndescription: 'Low level details about the framework'\n---\n\n# Low-level library internals\n\n## Under the hood of the `html!` macro\n\nThe `html!` macro turns code written in a custom HTML-like syntax into valid Rust code. Using this\nmacro is not necessary for developing Yew applications, but it is recommended. The code generated\nby this macro makes use of the public Yew library API which can be used directly if you wish. Note\nthat some methods used are undocumented intentionally to avoid accidental misuse. With each\nupdate of `yew-macro`, the generated code will be more efficient and handle any breaking changes\nwithout many (if any) modifications to the `html!` syntax.\n\nBecause the `html!` macro allows you to write code in a declarative style, your UI layout code will\nclosely match the HTML that is generated for the page. This becomes increasingly useful as your\napplication gets more interactive and your codebase gets larger. Rather than manually writing\nall of the code to manipulate the DOM yourself, the macro will handle it for you.\n\nUsing the `html!` macro can feel pretty magical, but it has nothing to hide. If you are curious about\nhow it works, try expanding the `html!` macro calls in your program. There is a useful command called\n`cargo expand` which allows you to see the expansion of Rust macros. `cargo expand` does not ship with\n`cargo` by default so you will need to install it with `cargo install cargo-expand` if you have not\nalready. [Rust-Analyzer](https://rust-analyzer.github.io/) also provides a mechanism for\n[obtaining macro output from within an IDE](https://rust-analyzer.github.io/manual.html#expand-macro-recursively).\n\nOutput from the `html!` macro is often pretty terse! This is a feature: machine-generated code can\nsometimes clash with other code in an application. To prevent issues, `proc_macro`\n\"hygiene\" is adhered to. Some examples include:\n\n1. Instead of using `yew::<module>` the macro generates `::yew::<module>` to make sure that the\n   Yew package is referenced correctly. This is also why `::alloc::vec::Vec::new()` is called instead\n   of just `Vec::new()`.\n2. Due to potential trait method name collisions, `<Type as Trait>` is used to make sure that we are\n   using members from the correct trait.\n\n## What is a virtual DOM?\n\nThe DOM (\"document object model\") is a representation of the HTML content that is managed by the browser\nfor your web page. A \"virtual\" DOM is simply a copy of the DOM that is held in application memory. Managing\na virtual DOM results in a higher memory overhead, but allows for batching and faster reads by avoiding\nor delaying the use of browser APIs.\n\nHaving a copy of the DOM in memory can be helpful for libraries that promote the use of\ndeclarative UIs. Rather than needing specific code for describing how the DOM should be modified\nin response to a user event, the library can use a generalized approach with DOM \"diffing\". When a Yew\ncomponent is updated and wants to change how it is rendered, the Yew library will build a second copy\nof the virtual DOM and directly compare it to a virtual DOM which mirrors what is currently on screen.\nThe \"diff\" (or difference) between the two can be broken down into incremental updates and applied in\na batch with browser APIs. Once the updates are applied, the old virtual DOM copy is discarded and the\nnew copy is saved for future diff checks.\n\nThis \"diff\" algorithm can be optimized over time to improve the performance of complex applications.\nSince Yew applications are run with WebAssembly, we believe that Yew has a competitive edge to adopt\nmore sophisticated algorithms in the future.\n\nThe Yew virtual DOM is not exactly one-to-one with the browser DOM. It also includes \"lists\" and\n\"components\" for organizing DOM elements. A list can simply be an ordered list of elements but can\nalso be much more powerful. By annotating each list element with a \"key\", application developers\ncan help Yew make additional optimizations to ensure that when a list changes, the least amount\nof work is done to calculate the diff update. Similarly, components provide custom logic to\nindicate whether a re-render is required to help with performance.\n\n## Yew scheduler and component-scoped event loop\n\n_Contribute to the docs – explain how `yew::scheduler` and `yew::html::scope` work in depth_\n\n## Further reading\n\n- [More information about macros from the Rust Book](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)\n- [More information about `cargo-expand`](https://github.com/dtolnay/cargo-expand)\n- [The API documentation for `yew::virtual_dom`](https://docs.rs/yew/*/yew/virtual_dom/index.html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/immutable.mdx",
    "content": "---\ntitle: 'Immutable Types'\ndescription: 'Immutable data structures for Yew'\n---\n\n## What are immutable types?\n\nThese are types that you can instantiate but never mutate the values. In order\nto update a value, you must instantiate a new value.\n\n## Why using immutable types?\n\nProperties, like in React, are propagated from ancestors to\nchildren. This means that the properties must live when each component is\nupdated. This is why properties should —ideally— be cheap to clone. To\nachieve this we usually wrap things in `Rc`.\n\nImmutable types are a great fit for holding property's values because they can\nbe cheaply cloned when passed from component to component.\n\n## Common Immutable Types\n\nYew recommends using the following immutable types from the `implicit-clone` crate:\n\n- `IString` (aliased as `AttrValue` in Yew) - for strings instead of `String`\n- `IArray<T>` - for arrays/vectors instead of `Vec<T>`\n- `IMap<K, V>` - for maps instead of `HashMap<K, V>`\n\nThese types are either reference-counted (`Rc`) or static references, making them very cheap to clone.\n\n## Further reading\n\n- [Immutable example](https://github.com/yewstack/yew/tree/master/examples/immutable)\n- [Crate `implicit-clone`](https://docs.rs/implicit-clone/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/optimizations.mdx",
    "content": "---\ntitle: 'Optimizations & Best Practices'\nsidebar_label: Optimizations\ndescription: 'Make your app faster'\n---\n\n## Using smart pointers effectively\n\n**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful\n[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**\n\nTo avoid cloning large amounts of data to create props when re-rendering, we can use\nsmart pointers to only clone a reference to the data instead of the data itself. If you pass\nreferences to the relevant data in your props and child components instead of the actual data you\ncan avoid cloning any data until you need to modify it in the child component, where you can\nuse `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.\n\nThis brings further benefits in `Component::changed` when working out whether prop changes require\nthe component to re-render. This is because instead of comparing the value of the data the\nunderlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can\ninstead be compared; if two pointers point to the same data then the value of the data they point to\nmust be the same. Note that the inverse might not be true! Even if two pointer addresses differ the\nunderlying data might still be the same - in this case you should compare the underlying data.\n\nTo do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is\nautomatically used when comparing data using the equality operator `==`). The Rust documentation\nhas [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).\n\nThis optimization is most useful for data types that don't implement `Copy`. If you can copy your\ndata cheaply, then it isn't worth putting it behind a smart pointer. For structures that\ncan be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring\nperformance improvements.\n\nThis optimization works best if the values are never updated by the children, and even better if\nthey are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values\nin pure components.\n\nHowever, it must be noted that unless you need to clone the data yourself in the child component,\nthis optimization is not only useless, but it also adds the unnecessary cost of reference counting. Props\nin Yew are already reference counted and no data clones occur internally.\n\n## View functions\n\nFor code readability reasons, it often makes sense to migrate sections of `html!` to their own\nfunctions. Not only does this make your code more readable because it reduces the amount of\nindentation present, it also encourages good design patterns – particularly around building\ncomposable applications because these functions can be called in multiple places which reduces the\namount of code that has to be written.\n\n## Pure Components\n\nPure components are components that don't mutate their state, only displaying content and\npropagating messages up to normal, mutable components. They differ from view functions in that they\ncan be used from within the `html!` macro using the component syntax \\(`<SomePureComponent />`\\)\ninstead of expression syntax \\(`{some_view_function()}`\\), and that depending on their\nimplementation, they can be memoized (this means that once a function is called its value is \"saved\"\nso that if it's called with the same arguments more than once it doesn't have to recompute its value\nand can just return the saved value from the first function call) - preventing re-renders for\nidentical props. Yew compares the props internally and so the UI is only re-rendered if the props change.\n\n## Reducing compile time using workspaces\n\nArguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time\ntaken to compile a project seems to be related to the quantity of code passed to the `html!` macro.\nThis tends to not be much of an issue for smaller projects, but for larger applications, it makes\nsense to split code across multiple crates to minimize the amount of work the compiler has to do for\neach change made to the application.\n\nOne possible approach is to make your main crate handle routing/page selection, and then make a\ndifferent crate for each page, where each page could be a different component or just a big\nfunction that produces `Html`. Code that is shared between the crates containing different parts of\nthe application could be stored in a separate crate which the project depends on.\nIn the best-case scenario, you go from rebuilding all of your code on each compile to rebuilding\nonly the main crate, and one of your page crates. In the worst case, where you edit something in the\n\"common\" crate, you will be right back to where you started: compiling all code that depends on that\ncommonly shared crate, which is probably everything else.\n\nIf your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \\(eg.\na page that renders on top of another page\\), you can use an example crate to create a simplified\nimplementation of the main page and additionally render the component you are working on.\n\n## Reducing binary sizes\n\n- optimize Rust code\n- `cargo.toml` \\( defining release profile \\)\n- optimize wasm code using `wasm-opt`\n\n**Note: more information about reducing binary sizes can be found in the\n[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**\n\n### Cargo.toml\n\nIt is possible to configure release builds to be smaller using the available settings in the\n`[profile.release]` section of your `Cargo.toml`.\n\n```toml, title=Cargo.toml\n[profile.release]\n# less code to include into binary\npanic = 'abort'\n# optimization over all codebase ( better optimization, slower build )\ncodegen-units = 1\n# optimization for size ( more aggressive )\nopt-level = 'z'\n# optimization for size\n# opt-level = 's'\n# link time optimization using using whole-program analysis\nlto = true\n```\n\n### Nightly Cargo configuration\n\nYou can also gain additional benefits from experimental nightly features of rust and\ncargo. To use the nightly toolchain with `trunk`, set the `RUSTUP_TOOLCHAIN=\"nightly\"` environment\nvariable. Then, you can configure unstable rustc features in your `.cargo/config.toml`.\nRefer to the doc of [unstable features], specifically the section about [`build-std`] and\n[`build-std-features`], to understand the configuration.\n\n```toml, title=\".cargo/config.toml\"\n[unstable]\n# Requires the rust-src component. `rustup +nightly component add rust-src`\nbuild-std = [\"std\", \"panic_abort\"]\nbuild-std-features = [\"panic_immediate_abort\"]\n```\n\n[unstable features]: https://doc.rust-lang.org/cargo/reference/unstable.html\n[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std\n[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features\n\n:::caution\nThe nightly rust compiler can contain bugs, such as [this one](https://github.com/yewstack/yew/issues/2696),\nthat require occasional attention and tweaking. Use these experimental options with care.\n:::\n\n### wasm-opt\n\nFurther, it is possible to optimize the size of `wasm` code.\n\nThe Rust Wasm Book has a section about reducing the size of Wasm binaries:\n[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)\n\n- using `wasm-pack` which by default optimizes `wasm` code in release builds\n- using `wasm-opt` directly on `wasm` files.\n\n```text\nwasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm\n```\n\n#### Build size of 'minimal' example in yew/examples/\n\nNote: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.\n\n| used tool                   | size  |\n| :-------------------------- | :---- |\n| wasm-bindgen                | 158KB |\n| wasm-bindgen + wasm-opt -Os | 116KB |\n| wasm-pack                   | 99 KB |\n\n## Further reading\n\n- [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)\n- [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)\n- [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)\n- [binaryen project](https://github.com/WebAssembly/binaryen)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/portals.mdx",
    "content": "---\ntitle: 'Portals'\ndescription: 'Rendering into out-of-tree DOM nodes'\n---\n\n## What is a portal?\n\nPortals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.\n`yew::create_portal(child, host)` returns an `Html` value that renders `child` not hierarchically under its parent component,\nbut as a child of the `host` element.\n\n## Usage\n\nTypical uses of portals can include modal dialogs and hovercards, as well as more technical applications\nsuch as controlling the contents of an element's\n[`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot), appending\nstylesheets to the surrounding document's `<head>` and collecting referenced elements inside a\ncentral `<defs>` element of an `<svg>`.\n\nNote that `yew::create_portal` is a low-level building block. Libraries should use it to implement\nhigher-level APIs which can then be consumed by applications. For example, here is a\nsimple modal dialogue that renders its `children` into an element outside `yew`'s control,\nidentified by the `id=\"modal_host\"`.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct ModalProps {\n    #[prop_or_default]\n    pub children: Html,\n}\n\n#[component]\nfn Modal(props: &ModalProps) -> Html {\n    let modal_host = gloo::utils::document()\n        .get_element_by_id(\"modal_host\")\n        .expect(\"Expected to find a #modal_host element\");\n\n    create_portal(\n        props.children.clone(),\n        modal_host.into(),\n    )\n}\n```\n\n## Event handling\n\nEvents emitted on elements inside portals follow the virtual DOM when bubbling up. That is,\nif a portal is rendered as the child of an element, then an event listener on that element\nwill catch events dispatched from inside the portal, even if the portal renders its contents\nin an unrelated location in the actual DOM.\n\nThis allows developers to be oblivious of whether a component they consume, is implemented with\nor without portals. Events fired on its children will bubble up regardless.\n\nA known issue is that events from portals into **closed** shadow roots will be dispatched twice,\nonce targeting the element inside the shadow root and once targeting the host element itself. Keep\nin mind that **open** shadow roots work fine. If this impacts you, feel free to open a bug report\nabout it.\n\n## SSR limitation\n\nPortals are **not rendered during server-side rendering**. They require a live\nDOM host element (`web_sys::Element`) which is unavailable on the server.\nIf you need to render content into `<head>` during SSR, see the\n[head rendering section](./server-side-rendering#rendering-head-tags)\nin the SSR documentation.\n\n## Further reading\n\n- [Portals example](https://github.com/yewstack/yew/tree/master/examples/portals)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/server-side-rendering.mdx",
    "content": "---\ntitle: 'Server-side Rendering'\ndescription: 'Render Yew on the server-side.'\n---\n\n# Server-side Rendering\n\nBy default, Yew components render on the client side. When a viewer\nvisits a website, the server sends a skeleton HTML file without any actual\ncontent and a WebAssembly bundle to the browser.\nEverything is rendered on the client side by the WebAssembly\nbundle. This is known as client-side rendering.\n\nThis approach works fine for most websites, with some caveats:\n\n1. Users will not be able to see anything until the entire WebAssembly\n   bundle is downloaded and the initial render has been completed.\n   This can result in a poor experience for users on a slow network.\n2. Some search engines do not support dynamically rendered web content and\n   those who do usually rank dynamic websites lower in the search results.\n\nTo solve these problems, we can render our website on the server side.\n\n## How it Works\n\nYew provides a `ServerRenderer` to render pages on the\nserver side.\n\nTo render Yew components on the server side, you can create a renderer\nwith `ServerRenderer::<App>::new()` and call `renderer.render().await`\nto render `<App />` into a `String`.\n\n```rust\nuse yew::prelude::*;\nuse yew::ServerRenderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\n// we use `flavor = \"current_thread\"` so this snippet can be tested in CI,\n// where tests are run in a WASM environment. You likely want to use\n// the (default) `multi_thread` favor as:\n// #[tokio::main]\n#[tokio::main(flavor = \"current_thread\")]\nasync fn no_main() {\n    let renderer = ServerRenderer::<App>::new();\n\n    let rendered = renderer.render().await;\n\n    // Prints: <div>Hello, World!</div>\n    println!(\"{}\", rendered);\n}\n```\n\n## Component Lifecycle\n\nThe recommended way of working with server-side rendering is\nfunction components.\n\nAll hooks other than `use_effect` (and `use_effect_with`)\nwill function normally until a component successfully renders into `Html`\nfor the first time.\n\n:::caution Web APIs are not available!\n\nWeb APIs such as `web_sys` are not available when your component is\nrendering on the server side.\nYour application will panic if you try to use them.\nYou should isolate logics that need Web APIs in `use_effect` or\n`use_effect_with` as effects are not executed during server-side rendering.\n\n:::\n\n:::danger Struct Components\n\nWhile it is possible to use Struct Components with server-side rendering,\nthere are no clear boundaries between client-side safe logic like the\n`use_effect` hook for function components and lifecycle events are invoked\nin a different order than the client side.\n\nIn addition, Struct Components will continue to accept messages until all of its\nchildren are rendered and `destroy` method is called. Developers need to\nmake sure no messages possibly passed to components would link to logic\nthat makes use of Web APIs.\n\nWhen designing an application with server-side rendering support,\nprefer function components unless you have a good reason not to.\n\n:::\n\n## Data Fetching during Server-side Rendering\n\nData fetching is one of the difficult points with server-side rendering and hydration.\n\nTraditionally, when a component renders, it is instantly available\n(outputs a virtual DOM to be rendered). This works fine when the\ncomponent does not want to fetch any data. But what happens if the component\nwants to fetch some data during rendering?\n\nIn the past, there was no mechanism for Yew to detect whether a component is still\nfetching data. The data-fetching client is responsible to implement\na solution to detect what is being requested during the initial render and triggers\na second render after requests are fulfilled. The server repeats this process until\nno more pending requests are added during a render before returning a response.\n\nThis not only wastes CPU resources by repeatedly rendering components,\nbut the data client also needs to provide a way to make the data fetched on the\nserver side available during the hydration process to make sure that the\nvirtual DOM returned by the initial render is consistent with the\nserver-side rendered DOM tree which can be hard to implement.\n\nYew takes a different approach by trying to solve this issue with `<Suspense />`.\n\nSuspense is a special component that when used on the client side, provides a\nway to show a fallback UI while the component is fetching\ndata (suspended) and resumes to normal UI when the data fetching completes.\n\nWhen the application is rendered on the server side, Yew waits until a\ncomponent is no longer suspended before serializing it into the string\nbuffer.\n\nDuring the hydration process, elements within a `<Suspense />` component\nremains dehydrated until all of its child components are no longer\nsuspended.\n\nWith this approach, developers can build a client-agnostic, SSR-ready\napplication with data fetching with very little effort.\n\n## Rendering `<head>` Tags\n\nA common need with SSR is rendering dynamic `<head>` content (e.g. `<title>`,\n`<meta>`) so that crawlers and social previews see the right metadata on first\nload.\n\n`ServerRenderer` only renders your component tree (typically at the body of the document),\nit has no access to `<head>`. Head tags must therefore be generated **on the server, outside of\nYew**, and spliced into the HTML template before it is sent to the client.\n\nThe [`ssr_router` example](https://github.com/yewstack/yew/blob/master/examples/ssr_router/src/bin/ssr_router_server.rs) demonstrates this pattern: the server recognizes the\nroute from the request URL, generates the appropriate `<title>` and `<meta>`\ntags, and injects them into the Trunk-generated `index.html` before\n`</head>`.\n\n:::info\n\nFor a fully SSR-compatible third-party solution, use [the `<Helmet/>` component from Bounce](https://docs.rs/bounce/latest/bounce/helmet/index.html).\n\n:::\n\n## SSR Hydration\n\nHydration is the process that connects a Yew application to the\nserver-side generated HTML file. By default, `ServerRender` prints\nhydratable HTML string which includes additional information to facilitate hydration.\nWhen the `Renderer::hydrate` method is called, instead of starting rendering from\nscratch, Yew will reconcile the Virtual DOM generated by the application\nwith the HTML string generated by the server renderer.\n\n:::caution\n\nTo successfully hydrate an HTML representation created by the\n`ServerRenderer`, the client must produce a Virtual DOM layout that\nexactly matches the one used for SSR including components that do not\ncontain any elements. If you have any component that is only useful in\none implementation, you may want to use a `PhantomComponent` to fill the\nposition of the extra component.\n:::\n\n:::warning\n\nThe hydration can only succeed if the real DOM matches the expected DOM\nafter initial render of the SSR output (static HTML) by browser. If your HTML is\nnot spec-compliant, the hydration _may_ fail. Browsers may change the DOM structure\nof the incorrect HTML, causing the actual DOM to be different from the expected DOM.\nFor example, [if you have a `<table>` without a `<tbody>`, the browser may add a `<tbody>` to the DOM](https://github.com/yewstack/yew/issues/2684)\n:::\n\n## Component Lifecycle during hydration\n\nDuring Hydration, components schedule 2 consecutive renders after it is\ncreated. Any effects are called after the second render completes.\nIt is important to make sure that the render function of your\ncomponent is free of side effects. It should not mutate any states or trigger\nadditional renders. If your component currently mutates states or triggers\nadditional renders, move them into a `use_effect` hook.\n\nIt is possible to use Struct Components with server-side rendering in\nhydration, the view function will be called\nmultiple times before the rendered function will be called.\nThe DOM is considered as not connected until the rendered function is called,\nyou should prevent any access to rendered nodes\nuntil `rendered()` method is called.\n\n## Example\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::Renderer;\n\n#[component]\nfn App() -> Html {\n    html! {<div>{\"Hello, World!\"}</div>}\n}\n\nfn main() {\n    let renderer = Renderer::<App>::new();\n\n    // hydrates everything under body element, removes trailing\n    // elements (if any).\n    renderer.hydrate();\n}\n```\n\nExample: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr)\nExample: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router)\n\n## Single thread mode\n\nYew supports single thread mode for server-side rendering by `yew::LocalServerRenderer`. This mode would work in a single thread environment like WASI.\n\n```rust\n// Build using `wasm32-wasip1` target or `wasm32-wasip2` target.\n\nuse yew::prelude::*;\nuse yew::LocalServerRenderer;\n\n#[component]\nfn App() -> Html {\n    use yew_router::prelude::*;\n\n    html! {\n        <>\n            <h1>{\"Yew WASI SSR demo\"}</h1>\n        </>\n    }\n}\n\npub async fn render() -> String {\n    let renderer = LocalServerRenderer::<App>::new();\n    let html_raw = renderer.render().await;\n\n    let mut body = String::new();\n    body.push_str(\"<body>\");\n    body.push_str(\"<div id='app'>\");\n    body.push_str(&html_raw);\n    body.push_str(\"</div>\");\n    body.push_str(\"</body>\");\n\n    body\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() {\n    println!(\"{}\", render().await);\n}\n```\n\nExample: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module)\n\n:::note\nIf you are using the `wasm32-unknown-unknown` target to build a SSR application, you can use the `not_browser_env` feature flag to disable access of browser-specific APIs inside of Yew. This would be useful on serverless platforms like Cloudflare Worker.\n:::\n\n:::caution\n\nServer-side rendering is currently experimental. If you find a bug, please file\nan issue on [GitHub](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=).\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\n## Callbacks\n\nCallbacks are used to communicate with services, agents, and parent components within Yew.\nInternally their type is just `Fn` wrapped in `Rc` to allow them to be cloned.\n\nThey have an `emit` function that takes their `<IN>` type as an argument and converts that to a message expected by its destination. If a callback from a parent is provided in props to a child component, the child can call `emit` on the callback in its `update` lifecycle hook to send a message back to its parent. Closures or Functions provided as props inside the `html!` macro are automatically converted to Callbacks.\n\nA simple use of a callback might look something like this:\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Clicked,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-next-line\n        let onclick = ctx.link().callback(|_| Msg::Clicked);\n        html! {\n            // highlight-next-line\n            <button {onclick}>{ \"Click\" }</button>\n        }\n    }\n}\n```\n\nThe function passed to `callback` must always take a parameter. For example, the `onclick` handler requires a function that takes a parameter of type `MouseEvent`. The handler can then decide what kind of message should be sent to the component. This message is scheduled for the next update loop unconditionally.\n\nIf you need a callback that might not need to cause an update, use `batch_callback`.\n\n```rust\nuse yew::{events::KeyboardEvent, html, Component, Context, Html};\n\nenum Msg {\n    Submit,\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // highlight-start\n        let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| {\n            if event.key() == \"Enter\" {\n                Some(Msg::Submit)\n            } else {\n                None\n            }\n        });\n\n        html! {\n            <input type=\"text\" {onkeypress} />\n        }\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter)\n- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/hoc.mdx",
    "content": "---\ntitle: 'Higher Order Components'\n---\n\nThere are several cases where Struct components do not directly support a feature (ex. Suspense) or require a lot of boilerplate code to use the features (ex. Context).\n\nIn those cases, it is recommended to create function components that are higher-order components.\n\n## Higher Order Components Definition\n\nHigher Order Components are components that do not add any new HTML and only wrap some other components to provide extra functionality.\n\n### Example\n\nHook into Context and pass it down to a struct component\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            <ThemedButtonHOC />\n        </ContextProvider<Theme>>\n    }\n}\n\n// highlight-start\n#[component]\npub fn ThemedButtonHOC() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {<ThemedButtonStructComponent {theme} />}\n}\n// highlight-end\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub theme: Theme,\n}\n\nstruct ThemedButtonStructComponent;\n\nimpl Component for ThemedButtonStructComponent {\n    type Message = ();\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let theme = &ctx.props().theme;\n        html! {\n            <button style={format!(\n                    \"background: {}; color: {};\",\n                    theme.background,\n                    theme.foreground\n                )}\n            >\n                { \"Click me!\" }\n            </button>\n        }\n    }\n}\n\n\n\n\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/introduction.mdx",
    "content": "---\ntitle: 'Introduction'\ndescription: 'Components in Yew'\n---\n\n## What are Components?\n\nComponents are the building blocks of Yew. They manage an internal state and can render elements to the DOM.\nComponents are created by implementing the `Component` trait for a type.\n\n## Writing Component's markup\n\nYew uses Virtual DOM to render elements to the DOM. The Virtual DOM tree can be constructed by using the\n`html!` macro. `html!` uses a syntax which is similar to HTML but is not the same. The rules are also\nmuch stricter. It also provides superpowers like conditional rendering and rendering of lists using iterators.\n\n:::info\n[Learn more about the `html!` macro, how it is used and its syntax](concepts/html/introduction.mdx)\n:::\n\n## Passing data to a component\n\nYew components use _props_ to communicate between parents and children. A parent component may pass any data as props to\nits children. Props are similar to HTML attributes but any Rust type can be passed as props.\n\n:::info\n[Learn more about the props](advanced-topics/struct-components/properties.mdx)\n:::\n\n:::info\nFor other than parent/child communication, use [contexts](../../concepts/contexts.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/lifecycle.mdx",
    "content": "---\ntitle: 'Lifecycle'\ndescription: 'Components and their lifecycle hooks'\n---\n\nThe `Component` trait has a number of methods which need to be implemented; Yew will call these at different\nstages in the lifecycle of a component.\n\n## Lifecycle\n\n:::important contribute\n`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/yew/issues/1915)\n:::\n\n## Lifecycle Methods\n\n### Create\n\nWhen a component is created, it receives properties from its parent component and is stored within\nthe `Context<Self>` that is passed down to the `create` method. The properties can be used to\ninitialize the component's state and the \"link\" can be used to register callbacks or send messages to the component.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\n#[derive(PartialEq, Properties)]\npub struct Props;\n\npub struct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = Props;\n\n    // highlight-start\n    fn create(ctx: &Context<Self>) -> Self {\n        MyComponent\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n}\n```\n\n### View\n\nThe `view` method allows you to describe how a component should be rendered to the DOM. Writing\nHTML-like code using Rust functions can become quite messy, so Yew provides a macro called `html!`\nfor declaring HTML and SVG nodes (as well as attaching attributes and event listeners to them) and a\nconvenient way to render child components. The macro is somewhat similar to React's JSX (the\ndifferences in programming language aside).\nOne difference is that Yew provides a shorthand syntax for properties, similar to Svelte, where instead of writing `onclick={onclick}`, you can just write `{onclick}`.\n\n```rust\nuse yew::{Component, Context, html, Html, Properties};\n\nenum Msg {\n    Click,\n}\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    button_text: String,\n}\n\nstruct MyComponent;\n\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    // highlight-start\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        let onclick = ctx.link().callback(|_| Msg::Click);\n        html! {\n            <button {onclick}>{ &ctx.props().button_text }</button>\n        }\n    }\n    // highlight-end\n}\n```\n\nFor usage details, check out [the `html!` guide](concepts/html/introduction.mdx).\n\n### Rendered\n\nThe `rendered` component lifecycle method is called once `view` has been called and Yew has rendered\nthe results to the DOM, but before the browser refreshes the page. This method is useful when you\nwant to perform actions that can only be completed after the component has rendered elements. There\nis also a parameter called `first_render` which can be used to determine whether this function is\nbeing called on the first render, or instead a subsequent one.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::{\n    Component, Context, html, Html, NodeRef,\n};\n\npub struct MyComponent {\n    node_ref: NodeRef,\n}\n\nimpl Component for MyComponent {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            <input ref={self.node_ref.clone()} type=\"text\" />\n        }\n    }\n\n    // highlight-start\n    fn rendered(&mut self, _ctx: &Context<Self>, first_render: bool) {\n        if first_render {\n            if let Some(input) = self.node_ref.cast::<HtmlInputElement>() {\n                input.focus();\n            }\n        }\n    }\n    // highlight-end\n}\n```\n\n:::tip note\nNote that this lifecycle method does not require implementation and will do nothing by default.\n:::\n\n### Update\n\nCommunication with components happens primarily through messages which are handled by the\n`update` lifecycle method. This allows the component to update itself\nbased on what the message was, and determine if it needs to re-render itself. Messages can be sent\nby event listeners, child components, Agents, Services, or Futures.\n\nHere is an example of what an implementation of `update` could look like:\n\n```rust\nuse yew::{Component, Context, html, Html};\n\n// highlight-start\npub enum Msg {\n    SetInputEnabled(bool)\n}\n// highlight-end\n\nstruct MyComponent {\n    input_enabled: bool,\n}\n\nimpl Component for MyComponent {\n    // highlight-next-line\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            input_enabled: false,\n        }\n    }\n\n    // highlight-start\n    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {\n        match msg {\n            Msg::SetInputEnabled(enabled) => {\n                if self.input_enabled != enabled {\n                    self.input_enabled = enabled;\n                    true // Re-render\n                } else {\n                    false\n                }\n            }\n        }\n    }\n    // highlight-end\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // impl\n        }\n    }\n\n}\n```\n\n### Changed\n\nComponents may be re-rendered by their parents. When this happens, they could receive new properties\nand need to re-render. This design facilitates parent-to-child component communication by just\nchanging the values of a property. There is a default implementation that re-renders the component\nwhen props are changed.\n\n### Destroy\n\nAfter Components are unmounted from the DOM, Yew calls the `destroy` lifecycle method; this is\nnecessary if you need to undertake operations to clean up after earlier actions of a component\nbefore it is destroyed. This method is optional and does nothing by default.\n\n### Infinite loops\n\nInfinite loops are possible with Yew's lifecycle methods but are only caused when trying to update\nthe same component after every render, when that update also requests the component to be rendered.\n\nA simple example can be seen below:\n\n```rust\nuse yew::{Context, Component, Html};\n\nstruct Comp;\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {\n        // We are going to always request to re-render on any msg\n        true\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        // For this example it doesn't matter what is rendered\n        Html::default()\n    }\n\n    fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {\n        // Request that the component is updated with this new msg\n        ctx.link().send_message(());\n    }\n}\n```\n\nLet's run through what happens here:\n\n1. Component is created using the `create` function.\n2. The `view` method is called so Yew knows what to render to the browser DOM.\n3. The `rendered` method is called, which schedules an update message using the `Context` link.\n4. Yew finishes the post-render phase.\n5. Yew checks for scheduled events and sees the update message queue is not empty so works through\n   the messages.\n6. The `update` method is called which returns `true` to indicate something has changed and the\n   component needs to re-render.\n7. Jump back to 2.\n\nYou can still schedule updates in the `rendered` method and it is often useful to do so, but\nconsider how your component will terminate this loop when you do.\n\n## Associated Types\n\nThe `Component` trait has two associated types: `Message` and `Properties`.\n\n```rust ,ignore\nimpl Component for MyComponent {\n    type Message = Msg;\n    type Properties = Props;\n\n    // ...\n}\n```\n\nThe `Message` type is used to send messages to a component after an event has taken place; for\nexample, you might want to undertake some action when a user clicks a button or scrolls down the\npage. Because components tend to have to respond to more than one event, the `Message` type will\nnormally be an enum, where each variant is an event to be handled.\n\nWhen organizing your codebase, it is sensible to include the definition of the `Message` type in the\nsame module in which your component is defined. You may find it helpful to adopt a consistent naming\nconvention for message types. One option (though not the only one) is to name the types\n`ComponentNameMsg`, e.g. if your component was called `Homepage` then you might call the type\n`HomepageMsg`.\n\n```rust\nenum Msg {\n    Click,\n    FormInput(String)\n}\n```\n\n`Properties` represents the information passed to a component from its parent. This type must implement the `Properties` trait \\(usually by deriving it\\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten \"properties\" to \"props\". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method.\n\n:::info\n[Learn more about properties](./properties)\n:::\n\n## Lifecycle Context\n\nAll component lifecycle methods take a context object. This object provides a reference to the component's scope, which\nallows sending messages to a component and the props passed to the component.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nProperties enable child and parent components to communicate with each other.\nEvery component has an associated properties type which describes what is passed down from the parent.\nIn theory, this can be any type that implements the `Properties` trait, but in practice, there is no\nreason for it to be anything but a struct where each field represents a property.\n\n## Derive macro\n\nInstead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to\nautomatically generate the implementation instead.\nTypes for which you derive `Properties` must also implement `PartialEq`.\n\n### Field attributes\n\nWhen deriving `Properties`, all fields are required by default.\nThe following attributes allow you to give your props initial values which will be used unless they are set to another value.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n#### `#[prop_or_default]`\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n#### `#[prop_or(value)]`\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.\n\n#### `#[prop_or_else(function)]`\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\n\n## `PartialEq`\n\n`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method\nonly when they change.\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Example\n\n```rust\nuse yew::Properties;\n/// Importing the AttrValue from virtual_dom\nuse yew::virtual_dom::AttrValue;\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we are using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function does not specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n```\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::{props, Properties, virtual_dom::AttrValue};\n\n#[derive(Clone, PartialEq)]\npub enum LinkColor {\n    Blue,\n    Red,\n    Green,\n    Black,\n    Purple,\n}\n\nfn create_default_link_color() -> LinkColor {\n    LinkColor::Blue\n}\n\n#[derive(Properties, PartialEq)]\npub struct LinkProps {\n    /// The link must have a target.\n    href: AttrValue,\n    /// Also notice that we're using AttrValue instead of String\n    text: AttrValue,\n    /// Color of the link. Defaults to `Blue`.\n    #[prop_or_else(create_default_link_color)]\n    color: LinkColor,\n    /// The view function will not specify a size if this is None.\n    #[prop_or_default]\n    size: Option<u32>,\n    /// When the view function doesn't specify active, it defaults to true.\n    #[prop_or(true)]\n    active: bool,\n}\n\nimpl LinkProps {\n    /// Notice that this function receives href and text as String\n    /// We can use `AttrValue::from` to convert it to a `AttrValue`\n    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {\n        // highlight-start\n        props! {LinkProps {\n            href: AttrValue::from(href),\n            text: AttrValue::from(text),\n            size,\n        }}\n        // highlight-end\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/refs.mdx",
    "content": "---\ntitle: 'Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` keyword can be used inside of any HTML element or component to get the DOM `Element` that\nthe item is attached to. This can be used to make changes to the DOM outside of the `view` lifecycle\nmethod.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\nFor example, using a `NodeRef` in a component's `rendered` method allows you to make draw calls to\na canvas element after it has been rendered from `view`.\n\nThe syntax is:\n\n```rust\nuse web_sys::Element;\nuse yew::{html, Component, Context, Html, NodeRef};\n\nstruct Comp {\n    node_ref: NodeRef,\n}\n\nimpl Component for Comp {\n    type Message = ();\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self {\n            // highlight-next-line\n            node_ref: NodeRef::default(),\n        }\n    }\n\n    fn view(&self, _ctx: &Context<Self>) -> Html {\n        html! {\n            // highlight-next-line\n            <div ref={self.node_ref.clone()}></div>\n        }\n    }\n\n    fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {\n        // highlight-start\n        let has_attributes = self.node_ref\n            .cast::<Element>()\n            .unwrap()\n            .has_attributes();\n        // highlight-end\n    }\n}\n```\n\n## Relevant examples\n\n- [Node Refs](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/advanced-topics/struct-components/scope.mdx",
    "content": "---\ntitle: 'Scope'\ndescription: \"Component's Scope\"\n---\n\n## Component's `Scope<_>` API\n\nThe component \"`Scope`\" is the mechanism through which components can create callbacks and update themselves\nusing messages. We obtain a reference to this by calling `link()` on the context object passed to the component.\n\n### `send_message`\n\nSends a message to the component.\nMessages are handled by the `update` method which determines whether the component should re-render.\n\n### `send_message_batch`\n\nSends multiple messages to the component at the same time.\nThis is similar to `send_message` but if any of the messages cause the `update` method to return `true`,\nthe component will re-render after all messages in the batch have been processed.\n\nIf the given vector is empty, this function does nothing.\n\n### `callback`\n\nCreate a callback that will send a message to the component when it is executed.\nUnder the hood, it will call `send_message` with the message returned by the provided closure.\n\n```rust\nuse yew::{html, Component, Context, Html};\n\nenum Msg {\n    Text(String),\n}\n\nstruct Comp;\n\nimpl Component for Comp {\n\n    type Message = Msg;\n    type Properties = ();\n\n    fn create(_ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        // Create a callback that accepts some text and sends it\n        // to the component as the `Msg::Text` message variant.\n        // highlight-next-line\n        let cb = ctx.link().callback(|text: String| Msg::Text(text));\n\n        // The previous line is needlessly verbose to make it clearer.\n        // It can be simplified it to this:\n        // highlight-next-line\n        let cb = ctx.link().callback(Msg::Text);\n\n        // Will send `Msg::Text(\"Hello World!\")` to the component.\n        // highlight-next-line\n        cb.emit(\"Hello World!\".to_owned());\n\n        html! {\n            // html here\n        }\n    }\n}\n```\n\n### `batch_callback`\n\nCreate a callback that will send a batch of messages to the component when it is executed.\nThe difference to `callback` is that the closure passed to this method doesn't have to return a message.\nInstead, the closure can return either `Vec<Msg>` or `Option<Msg>` where `Msg` is the component's message type.\n\n`Vec<Msg>` is treated as a batch of messages and uses `send_message_batch` under the hood.\n\n`Option<Msg>` calls `send_message` if it is `Some`. If the value is `None`, nothing happens.\nThis can be used in cases where, depending on the situation, an update isn't required.\n\nThis is achieved using the `SendAsMessage` trait which is only implemented for these types.\nYou can implement `SendAsMessage` for your own types which allows you to use them in `batch_callback`.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/agents.mdx",
    "content": "---\ntitle: 'Agents'\ndescription: \"Yew's Actor System\"\n---\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\nAgents are a way to offload tasks to web workers.\n\nIn order for agents to run concurrently, Yew uses\n[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).\n\n## Lifecycle\n\n<!--\nThe diagram is produced with nomnoml (nomnoml.com),\nThe code can be found in the <desc> tag of the svgs.\n-->\n\n<ThemedImage\n    alt=\"agent lifecycle diagram\"\n    sources={{\n        light: useBaseUrl('/img/agent-lifecycle-light.svg'),\n        dark: useBaseUrl('/img/agent-lifecycle-dark.svg'),\n    }}\n/>\n\n## Types of Agents\n\n### Reaches\n\n- Public - There will exist at most one instance of a Public Agent at any given time. Bridges will\n  spawn or connect to an already spawned agent in a web worker.\n  When no bridges are connected to this agent, the agent will disappear.\n\n- Private - Spawn a new agent in a web worker for every new bridge. This is good for moving shared but\n  independent behavior that communicates with the browser out of components. When\n  the connected bridge is dropped, the agent will disappear.\n\n- Global \\(WIP\\)\n\n## Communication between Agents and Components\n\n### Bridges\n\nA bridge allows bi-directional communication between an agent and a component. Bridges also allow agents to communicate with one another.\n\nA `use_bridge` hook is also provided to create bridges in a function component.\n\n### Dispatchers\n\nA dispatcher allows uni-directional communication between a component and an agent. A dispatcher allows a component to send messages to an agent.\n\n## Overhead\n\nAgents use web workers \\(i.e. Private and Public\\). They incur a serialization overhead on the\nmessages they send and receive. Agents use [bincode](https://github.com/bincode-org/bincode) to communicate\nwith other threads, so the cost is substantially higher than just calling a function.\n\n## Further reading\n\n- The [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) example shows how\n  components can send messages to and receive messages from agents.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/basic-web-technologies/css.mdx",
    "content": "---\ntitle: 'CSS with classes!'\ndescription: 'A handy macro to handle classes'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYew does not natively provide a CSS-in-Rust solution but helps with styling by providing\nprogrammatic ways to interact with the HTML `class` attribute.\n\n## `classes!` macro\n\nThe `classes!` macro and associated `Classes` struct simplify the use of HTML classes:\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(String::from(\"class-1 class-2\"))}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Slice\" label=\"Slice\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"].as_ref())}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\nWe will expand upon this concept in [more CSS](../../more/css).\n\n## Inline Styles\n\nCurrently Yew does not provide any special help with inline styles specified via the `style` attribute,\nbut you can use it like any other HTML attribute:\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div style=\"color: red;\"></div>\n};\n```\n\nWe will expand upon this concept in [more CSS](../../more/css).\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/basic-web-technologies/html.mdx",
    "content": "---\ntitle: 'HTML with html!'\ndescription: 'It is HTML but not quite!'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nYou can write expressions resembling HTML with the `html!` macro. Behind the scenes, Yew turns\nit into rust code representing the DOM to generate.\n\n```rust\nuse yew::prelude::*;\n\nlet my_header: Html = html! {\n    <img src=\"img_girl.jpg\" alt=\"Girl in a jacket\" width=\"500\" height=\"600\" />\n};\n```\n\nSimilar to format expressions, there is an easy way to embed values from the surrounding\ncontext into the HTML by applying curly brackets:\n\n```rust\nuse yew::prelude::*;\n\nlet header_text = \"Hello world\".to_string();\nlet header_html: Html = html! {\n    <h1>{header_text}</h1>\n};\n\nlet count: usize = 5;\nlet counter_html: Html = html! {\n    <p>{\"My age is: \"}{count}</p>\n};\n\nlet combined_html: Html = html! {\n    <div>{header_html}{counter_html}</div>\n};\n```\n\nOne major rule comes with the use of `html!` - you can only return 1 wrapping node.\nTo render a list of multiple elements, `html!` allows fragments. Fragments are tags\nwithout a name, that produce no HTML element by themselves.\n\n<Tabs>\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust , compile_fail\nuse yew::html;\n\n// error: only one root HTML element allowed\nhtml! {\n\n    <div></div>\n    <p></p>\n\n};\n```\n\n</TabItem>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::html;\n\n// fixed: using HTML fragments\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n```\n\n</TabItem>\n</Tabs>\n\nWe will introduce Yew and HTML further in depth in [more HTML](concepts/html/introduction.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/basic-web-technologies/js.mdx",
    "content": "---\ntitle: 'JS with RS'\ndescription: 'JavaScript with Rust'\ncomment: 'Keep this file as short and simple as possible. Its purpose is to ease the reader into components in Yew instead of providing proper API docs'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files, while also keeping the underlying technology\n> accessible where necessary.\n\nAs of today, WebAssembly is not feature-complete for DOM interactions. This means even in Yew we\nsometimes rely on calling JavaScript. What follows is an overview of the involved libraries.\n\n## wasm-bindgen\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool that bridges calls between JavaScript and Rust functions.\n\nWe highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./wasm-bindgen.mdx).\n\n## web-sys\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs and allows us to write JavaScript code in a rustyfied and safe way.\n\nExample:\n\n<Tabs>\n<TabItem value=\"JS\" label=\"JS\">\n\n```js\nlet document = window.document\n```\n\n</TabItem>\n\n<TabItem value=\"RS\" label=\"RS\">\n\n```rust ,no_run\nuse wasm_bindgen::UnwrapThrowExt;\nuse web_sys::window;\n\nlet document = window()\n    .expect_throw(\"window is undefined\")\n    .document()\n    .expect_throw(\"document is undefined\");\n```\n\n</TabItem>\n</Tabs>\n\nOnce again we highly recommend you take a look at their [documentation](https://wasm-bindgen.github.io/wasm-bindgen/) and our [quick guide](./web-sys.mdx).\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/basic-web-technologies/wasm-bindgen.mdx",
    "content": "---\ntitle: 'wasm-bindgen'\nsidebar_label: wasm-bindgen\n---\n\n[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) is a library and tool to facilitate\nhigh-level interactions between Wasm modules and JavaScript; it is built with Rust by\n[The Rust and WebAssembly Working Group](https://rustwasm.github.io/).\n\nYew uses `wasm-bindgen` to interact with the browser through a number of crates:\n\n- [`js-sys`](https://crates.io/crates/js-sys)\n- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n- [`web-sys`](https://crates.io/crates/web-sys)\n\nThis section will explore some of these crates at a high level, to make it easier to understand\nand use `wasm-bindgen` APIs with Yew. For a more in-depth guide to `wasm-bindgen` and its associated\ncrates then check out [The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/).\n\nFor documentation on the above crates check out [`wasm-bindgen docs.rs`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html).\n\n:::tip\nUse the `wasm-bindgen` doc.rs search to find browser APIs and JavaScript types that have been imported\nover using `wasm-bindgen`.\n:::\n\n## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen)\n\nThis crate provides many of the building blocks for the rest of the crates above. In this section we\nare only going to cover two main areas of the `wasm-bindgen` crate and that is the macro and some\ntypes/traits you will see pop up again and again.\n\n### `#[wasm_bindgen]` macro\n\nThe `#[wasm_bindgen]` macro provides an interface between Rust and JavaScript, providing a system\nfor translating between the two. Using this macro is more advanced, and you should not need to reach\nfor it unless you are trying to use an external JavaScript library. The `js-sys` and `web-sys`\ncrates expose `wasm-bindgen` definitions for built-in JavaScript types and browser APIs.\n\nLet's go over a simple example of using the `#[wasm-bindgen]` macro to import some specific flavours\nof the [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) function.\n\n```rust ,no_run\nuse wasm_bindgen::prelude::*;\n\n// First up let's take a look of binding `console.log` manually, without the\n// help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations\n// manually ourselves, and the correctness of our program relies on the\n// correctness of these annotations!\n#[wasm_bindgen]\nextern \"C\" {\n    // Use `js_namespace` here to bind `console.log(..)` instead of just\n    // `log(..)`\n    #[wasm_bindgen(js_namespace = console)]\n    fn log(s: &str);\n\n    // The `console.log` is quite polymorphic, so we can bind it with multiple\n    // signatures. Note that we need to use `js_name` to ensure we always call\n    // `log` in JS.\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_u32(a: u32);\n\n    // Multiple arguments too!\n    #[wasm_bindgen(js_namespace = console, js_name = log)]\n    fn log_many(a: &str, b: &str);\n}\n\n// using the imported functions!\nlog(\"Hello from Rust!\");\nlog_u32(42);\nlog_many(\"Logging\", \"many values!\");\n```\n\n_This example was adapted from [1.2 Using console.log of The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/console-log.html)_.\n\n### Simulating inheritance\n\nInheritance between JavaScript classes is a core feature of the Javascript language and the DOM\n(Document Object Model) is designed around it. When types are imported using `wasm-bindgen` you can\nalso add attributes that describe their inheritance.\n\nIn Rust, this inheritance is represented using the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\nand [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) traits. An example of this\nmight help; so say you have three types `A`, `B`, and `C` where `C` extends `B` which in turn\nextends `A`.\n\nWhen importing these types the `#[wasm-bindgen]` macro will implement the `Deref` and `AsRef`\ntraits in the following way:\n\n- `C` can `Deref` to `B`\n- `B` can `Deref` to `A`\n- `C` can be `AsRef` to `B`\n- Both `C` & `B` can be `AsRef` to `A`\n\nThese implementations allow you to call a method from `A` on an instance of `C` and to use `C` as if\nit was `&B` or `&A`.\n\nIt is important to note that every single type imported using `#[wasm-bindgen]` has the same root type,\nyou can think of it as the `A` in the example above, this type is [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) which has\nits section below.\n\n_[extends section in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_\n\n### [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\n\nThis is a representation of an object owned by JavaScript, this is a root catch-all type for `wasm-bindgen`.\nBecause JavaScript does not have a strong type system, any type that comes from `wasm-bindgen` is a `JsValue`.\nFunctions in JavaScript do not define the type of any variables they take in or return; variables can be\nany valid JavaScript value, hence `JsValue`. If you are working with imported functions or types that\naccept a `JsValue`, then any imported value is _technically_ valid.\n\nEven though `JsValue` may be accepted by a JS function, that function may still only _actually_ accept certain types.\nPassing an incorrect `JsValue` can lead to an exception which triggers a panic - so when using raw `wasm-bindgen` APIs,\ncheck the your JavaScript's documentation for types of inputs that will cause an exception (and a panic).\n\n_[`JsValue` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)._\n\n### [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\n\nRust has a strong type system and JavaScript...doesn't 😞. For Rust to maintain these\nstrong types but still be convenient, the WebAssembly group came up with a pretty neat trait `JsCast`.\nIts job is to help you move from one JavaScript \"type\" to another, which sounds vague, but it means\nthat if you have one type which you know is another, then you can use the functions of `JsCast`\nto jump from one type to the other. It is a nice trait to get to know when working with `web-sys`,\n`wasm_bindgen`, `js-sys` - you will notice lots of types will implement `JsCast` from those crates.\n\n`JsCast` provides both checked and unchecked methods of casting - so if at runtime if you are\nunsure what type a certain object is, you can try to cast it, which returns possible failure types like\n[`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) and\n[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).\n\nA common example of this in [`web-sys`](./web-sys.mdx) is when you are trying to get the\ntarget of an event. You might know what the target element is, but the\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API will always return an [`Option<web_sys::EventTarget>`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target).\nYou will need to cast it to the element type so you can call its methods.\n\n```rust\n// need to import the trait.\nuse wasm_bindgen::JsCast;\nuse web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement};\n\nfn handle_event(event: Event) {\n    let target: EventTarget = event\n        .target()\n        .expect(\"I'm sure this event has a target!\");\n\n    // maybe the target is a select element?\n    if let Some(select_element) = target.dyn_ref::<HtmlSelectElement>() {\n        // do something amazing here\n        return;\n    }\n\n    // if it wasn't a select element then I KNOW it's a input element!\n    let input_element: HtmlInputElement = target.unchecked_into();\n}\n```\n\nThe [`dyn_ref`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref)\nmethod is a checked cast that returns an `Option<&T>`, which means the original type\ncan be used again if the cast failed and thus returned `None`. The\n[`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nmethod will consume `self`, as per convention for `into` methods in Rust, and the type returned is\n`Result<T, Self>`. If the casting fails, the original `Self` value is returned in `Err`. You can try again\nor do something else with the original type.\n\n_[`JsCast` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._\n\n### [`Closure`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)\n\nThe `Closure` type provides a way to transfer Rust closures to JavaScript. The closures passed to\nJavaScript must have a `'static` lifetime for soundness reasons.\n\nThis type is a \"handle\" in the sense that whenever it is dropped, it will invalidate the JS\nclosure that it refers to. Any usage of the closure in JS after the Closure has been dropped will\nraise an exception.\n\n`Closure` is often used when you are working with a `js-sys` or `web-sys` API that accepts a type\n[`&js_sys::Function`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Function.html).\nAn example of using a `Closure` in Yew can be found in the [Using `Closure` section](../html/events.mdx#using-closure-verbose)\non the [Events](../html/events.mdx) page.\n\n_[`Closure` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._\n\n## [`js-sys`](https://crates.io/crates/js-sys)\n\nThe `js-sys` crate provides bindings/imports of JavaScript's standard, built-in objects, including\ntheir methods and properties.\n\nThis does not include any web APIs; that's what [`web-sys`](./web-sys.mdx) is for!\n\n_[`js-sys` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/index.html)._\n\n## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n\nThe `wasm-bindgen-futures` crate provides a bridge for working with JavaScript Promise types as a\nRust [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html), and contains\nutilities to turn a rust Future into a JavaScript Promise. This can be useful when working with\nasynchronous or otherwise blocking work in Rust (wasm), and provides the ability to interoperate\nwith JavaScript events and JavaScript I/O primitives.\n\nThere are three main interfaces in this crate currently:\n\n1. [`JsFuture`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) -\n   A type that is constructed with a [`Promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/js_sys/struct.Promise.html)\n   and can then be used as a `Future<Output=Result<JsValue, JsValue>>`. This `Future` will resolve to `Ok` if\n   the `Promise` is resolved and `Err` if the `Promise` is rejected, containing the resolved or rejected\n   value from the `Promise` respectively.\n\n2. [`future_to_promise`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) -\n   Converts a Rust `Future<Output=Result<JsValue, JsValue>>` into a\n   JavaScript `Promise`. The future’s result will translate to either a resolved or rejected\n   `Promise` in JavaScript.\n\n3. [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) -\n   Spawns a `Future<Output = ()>` on the current thread. This is the best way\n   to run a Future in Rust without sending it to JavaScript.\n\n_[`wasm-bindgen-futures` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._\n\n### [`spawn_local`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)\n\n`spawn_local` is going to be the most commonly used part of the `wasm-bindgen-futures` crate in Yew\nas this helps when using libraries that have async APIs.\n\n```rust ,no_run\nuse web_sys::console;\nuse wasm_bindgen_futures::spawn_local;\n\nasync fn my_async_fn() -> String { String::from(\"Hello\") }\n\nspawn_local(async {\n    let mut string = my_async_fn().await;\n    string.push_str(\", world!\");\n    // console log \"Hello, world!\"\n    console::log_1(&string.into());\n});\n```\n\nYew has also added support for futures in certain APIs, most notably you can create a\n`callback_future` which accepts an `async` block - this uses `spawn_local` internally.\n\n_[`spawn_local` documentation](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/basic-web-technologies/web-sys.mdx",
    "content": "---\ntitle: 'web-sys'\ndescription: 'The web-sys crate provides bindings for Web APIs.'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe [`web-sys` crate](https://crates.io/crates/web-sys) provides bindings for Web APIs. This is\nprocedurally generated from browser WebIDL which is why some names are so long and why some types are vague.\n\n## Features in `web-sys`\n\nThe `web-sys` crate with all of its features enabled can add lots of bloat to a Wasm application.\nTo get around this issue most types are feature gated so that you only include the types\nyou require for your application. Yew enables several features from `web-sys` and\nexposes some types in its public API. You will often need to add `web-sys` as a dependency yourself.\n\n## Inheritance in `web-sys`\n\nIn the [Simulating inheritance section](./wasm-bindgen.mdx#simulating-inheritance) you can read how in\ngeneral Rust provides an approach to simulate inheritance in JavaScript. This is very important in\n`web-sys` as understanding what methods are available on a type means understanding its inheritance.\n\nThis section is going to look at a specific element and list out its inheritance using Rust by\ncalling [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) until\nthe value is [`JsValue`](./wasm-bindgen.mdx#jsvalue):\n\n```rust\nuse std::ops::Deref;\nuse web_sys::{\n    Element,\n    EventTarget,\n    HtmlElement,\n    HtmlTextAreaElement,\n    Node,\n};\n\nfn inheritance_of_text_area(text_area: HtmlTextAreaElement) {\n    // HtmlTextAreaElement is <textarea> in html.\n    let html_element: &HtmlElement = text_area.deref();\n\n    let element: &Element = html_element.deref();\n\n    let node: &Node = element.deref();\n\n    let event_target: &EventTarget = node.deref();\n\n    // Notice we have moved from web-sys types now into built-in\n    // JavaScript types which are in the js-sys crate.\n    let object: &js_sys::Object = event_target.deref();\n\n    // Notice we have moved from js-sys type to the root JsValue from\n    // the wasm-bindgen crate.\n    let js_value: &wasm_bindgen::JsValue = object.deref();\n\n    // Using deref like this means we have to manually traverse\n    // the inheritance tree, however, you can call JsValue methods\n    // on the HtmlTextAreaElement type.\n    // The `is_string` method comes from JsValue.\n    assert!(!text_area.is_string());\n\n    // empty function just to prove we can pass HtmlTextAreaElement as a\n    // &EventTarget.\n    fn this_function_only_takes_event_targets(targets: &EventTarget) {};\n\n    // The compiler will walk down the deref chain in order to match the types here.\n    this_function_only_takes_event_targets(&text_area);\n\n    // The AsRef implementations allow you to treat the HtmlTextAreaElement\n    // as an &EventTarget.\n    let event_target: &EventTarget = text_area.as_ref();\n\n}\n```\n\n_[Inheritance in `web-sys` in The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/web-sys/inheritance.html)._\n\n## The `Node` in `NodeRef`\n\nYew uses a [`NodeRef`](concepts/function-components/node-refs.mdx) to provide a way for keeping a reference to\na `Node` made by the [`html!`](concepts/html/introduction.mdx) macro. The `Node` part of `NodeRef` is referring to\n[`web_sys::Node`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Node.html). The\n`NodeRef::get` method will return a `Option<Node>` value, however, most of the time in Yew you want\nto cast this value to a specific element so you can use its specific methods. This casting\ncan be done using [`JsCast`](./wasm-bindgen.mdx#JsCast) on the `Node` value, if present, but Yew\nprovides the `NodeRef::cast` method to perform this casting for convenience and so that you do not\nnecessarily have to include the `wasm-bindgen` dependency for the `JsCast` trait.\n\nThe two code blocks below do essentially the same thing, the first is using `NodeRef::cast` and\nthe second is using [`JsCast::dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\non the `web_sys::Node` returned from `NodeRef::get`.\n\n<Tabs>\n  <TabItem value=\"Using NodeRef::cast\" label=\"Using NodeRef::cast\">\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_node_ref_cast(node_ref: NodeRef) {\n    if let Some(input) = node_ref.cast::<HtmlInputElement>() {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"Using NodeRef::get\" label=\"Using NodeRef::get\">\n\n```rust\nuse wasm_bindgen::JsCast;\nuse web_sys::HtmlInputElement;\nuse yew::NodeRef;\n\nfn with_jscast(node_ref: NodeRef) {\n    if let Some(input) = node_ref\n        .get()\n        .and_then(|node| node.dyn_into::<HtmlInputElement>().ok()) {\n        // do something with HtmlInputElement\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## JavaScript example to Rust\n\nThis section demonstrates examples of how JavaScript code which interact with the\nWeb APIs can be rewritten with `web-sys` in Rust.\n\n### JavaScript example\n\n```js\ndocument.getElementById('mousemoveme').onmousemove = (e) => {\n    // e = Mouse event.\n    var rect = e.target.getBoundingClientRect()\n    var x = e.clientX - rect.left //x position within the element.\n    var y = e.clientY - rect.top //y position within the element.\n    console.log('Left? : ' + x + ' ; Top? : ' + y + '.')\n}\n```\n\n### `web-sys` example\n\nUsing `web-sys` alone the above JavaScript example could be implemented like this:\n\n```toml title=Cargo.toml\n[dependencies]\nwasm-bindgen = \"0.2\"\n\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable all the web-sys features we want to use!\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e: MouseEvent| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// we now need to save the `mousemove` Closure so that when\n// this event fires the closure is still in memory.\n```\n\nThis version is much more verbose, but you will probably notice part of that is because of failure\ntypes reminding us that some of these function calls have invariants that must be held, or otherwise will\ncause a panic in Rust. Another part of the verbosity is the calls to `JsCast` to cast into\ndifferent types so that you can call its specific methods.\n\n### Yew example\n\nIn Yew you will mostly be creating [`Callback`](concepts/function-components/callbacks.mdx)s to use in the\n[`html!`](concepts/html/introduction.mdx) macro so the example is going to use this approach instead of completely copying\nthe approach above:\n\n```toml title=Cargo.toml\n[dependencies.web-sys]\nversion = \"0.3\"\n# We need to enable the `DomRect` feature to use the\n# `get_bounding_client_rect` method.\nfeatures = [\n    \"console\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n\n```\n\n```rust\nuse web_sys::{console, HtmlElement, MouseEvent};\nuse yew::{\n    html,\n    Callback, TargetCast,\n};\n\nlet onmousemove = Callback::from(|e: MouseEvent| {\n    if let Some(target) = e.target_dyn_into::<HtmlElement>() {\n        let rect = target.get_bounding_client_rect();\n        let x = (e.client_x() as f64) - rect.left();\n        let y = (e.client_y() as f64) - rect.top();\n        console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n    }\n});\n\nhtml! {\n    <div id=\"mousemoveme\" {onmousemove}></div>\n};\n```\n\n## External libraries\n\n`web-sys` is a raw binding to the Web API so it comes with some pain in Rust because it was not\ndesigned with Rust or even a strong type system in mind, this is where community crates\nprovide abstractions over `web-sys` to provide more idiomatic Rust APIs.\n\n_[External libraries page](/community/external-libs)_\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/contexts.mdx",
    "content": "---\ntitle: 'Contexts'\nsidebar_label: Contexts\ndescription: 'Using contexts to pass deeply nested data'\n---\n\nUsually, data is passed from a parent component to a child component via props.\nBut passing props can become verbose and annoying if you have to pass them through many components in the middle,\nor if many components in your app need the same information. Context solves this problem by allowing a\nparent component to make data available to _any_ component in the tree below it, no matter how deep,\nwithout having to pass it down with props.\n\n## The problem with props: \"Prop Drilling\"\n\nPassing [props](./function-components/properties.mdx) is a great way to pass data directly from a parent to a child.\nThey become cumbersome to pass down through deeply nested component trees or when multiple components share the same data.\nA common solution to data sharing is lifting the data to a common ancestor and making the children take it as props.\nHowever, this can lead to cases where the prop has to go through multiple components to reach the component that needs it.\nThis situation is called \"Prop Drilling\".\n\nConsider the following example which passes down the theme using props:\n\n```rust\nuse yew::{html, Component, Context, Html, Properties, component};\n\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    foreground: String,\n    background: String,\n}\n\n#[derive(PartialEq, Properties)]\npub struct NavbarProps {\n    theme: Theme,\n}\n\n#[component]\nfn Navbar(props: &NavbarProps) -> Html {\n    html! {\n        <div>\n            <Title theme={props.theme.clone()}>\n                { \"App title\" }\n            </Title>\n            <NavButton theme={props.theme.clone()}>\n                { \"Somewhere\" }\n            </NavButton>\n        </div>\n    }\n}\n\n#[derive(PartialEq, Properties)]\npub struct ThemeProps {\n    theme: Theme,\n    children: Html,\n}\n\n#[component]\nfn Title(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n#[component]\nfn NavButton(_props: &ThemeProps) -> Html {\n    html! {\n        // impl\n    }\n}\n\n/// App root\n#[component]\nfn App() -> Html {\n    let theme = Theme {\n        foreground: \"yellow\".to_owned(),\n        background: \"pink\".to_owned(),\n    };\n\n    html! {\n        <Navbar {theme} />\n    }\n}\n```\n\nWe \"drill\" the theme prop through `Navbar` so that it can reach `Title` and `NavButton`.\nIt would be nice if `Title` and `NavButton`, the components that need access to the theme, can just access the theme\nwithout having to pass it to them as a prop. Contexts solve this problem by allowing a parent to pass data, theme in this case,\nto its children.\n\n## Using Contexts\n\n### Step 1: Providing the context\n\nA context provider is required to consume the context. `ContextProvider<T>`, where `T` is the context struct used as the provider.\n`T` must implement `Clone` and `PartialEq`. `ContextProvider` is the component whose children will have the context available to them.\nThe children are re-rendered when the context changes. A struct is used to define what data is to be passed. The `ContextProvider` can be used as:\n\n```rust\nuse yew::prelude::*;\n\n\n/// App theme\n#[derive(Clone, Debug, PartialEq)]\nstruct Theme {\n    foreground: String,\n    background: String,\n}\n\n/// Main component\n#[component]\npub fn App() -> Html {\n    let ctx = use_state(|| Theme {\n        foreground: \"#000000\".to_owned(),\n        background: \"#eeeeee\".to_owned(),\n    });\n\n    html! {\n        // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`\n        // so we deref it.\n        // It derefs to `&Theme`, hence the clone\n        <ContextProvider<Theme> context={(*ctx).clone()}>\n            // Every child here and their children will have access to this context.\n            <Toolbar />\n        </ContextProvider<Theme>>\n    }\n}\n\n/// The toolbar.\n/// This component has access to the context\n#[component]\npub fn Toolbar() -> Html {\n    html! {\n        <div>\n            <ThemedButton />\n        </div>\n    }\n}\n\n/// Button placed in `Toolbar`.\n/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access\n/// to the context.\n#[component]\npub fn ThemedButton() -> Html {\n    let theme = use_context::<Theme>().expect(\"no ctx found\");\n\n    html! {\n        <button style={format!(\"background: {}; color: {};\", theme.background, theme.foreground)}>\n            { \"Click me!\" }\n        </button>\n    }\n}\n```\n\n### Step 2: Consuming context\n\n#### Function components\n\n`use_context` hook is used to consume contexts in function components.\nSee [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.\n\n#### Struct components\n\nWe have 2 options to consume contexts in struct components:\n\n- [Higher Order Components](../advanced-topics/struct-components/hoc): A higher-order function component will consume the context and pass the data to the struct component which requires it.\n- Consume context directly in the struct component. See [example of struct component as a consumer](https://github.com/yewstack/yew/tree/master/examples/contexts/src/struct_component_subscriber.rs)\n\n## Use cases\n\nGenerally, if some data is needed by distant components in different parts of the tree, context will likely help you.\nHere are some examples of such cases:\n\n- **Theming**: You can put a context at the top of the app that holds your app theme and use it to adjust the visual appearance, as shown in the above example.\n- **Current user account**: In many cases, components need to know the currently logged-in user. You can use a context to provide the current user object to the components.\n\n### Considerations to make before using contexts\n\nContexts are very easy to use. That makes them very easy to misuse/overuse.\nJust because you can use a context to share props to components multiple levels deep, does not mean that you should.\n\nFor example, you may be able to extract a component and pass that component as a child to another component. For example,\nyou may have a `Layout` component that takes `articles` as a prop and passes it down to `ArticleList` component.\nYou should refactor the `Layout` component to take children as props and display `<Layout> <ArticleList {articles} /> </Layout>`.\n\n## Mutating the context value of a child\n\nBecause of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.\nTo mutate a context's value, we must combine it with a reducer. This is done by using the\n[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.\n\nThe [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts\nwith the help of contexts\n\n## Further reading\n\n- The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/callbacks.mdx",
    "content": "---\ntitle: 'Callbacks'\n---\n\nCallbacks are used to asynchronously communicate upwards the components tree and with other things like agents or the DOM during event handling.\nInternally their type is just an `Fn` wrapped in `Rc` to allow them to be cheaply cloned.\n\nThey have an `emit` function if you want to call them manually.\n\n```rust\nuse yew::{html, Component, Context, Html, Callback};\n\nlet cb: Callback<String, String> = Callback::from(move |name: String| {\n    format!(\"Bye {}\", name)\n});\n\nlet result = cb.emit(String::from(\"Bob\")); // call the callback\n// web_sys::console::log_1(&result.into()); // if uncommented will print \"Bye Bob\"\n```\n\n## Passing callbacks as props\n\nA common pattern in yew is to create a callback and pass it down as a prop.\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub on_name_entry: Callback<String>,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n\n    props.on_name_entry.emit(String::from(\"Bob\"));\n\n    html! { \"Hello\" }\n}\n\n// Then supply the prop\n#[component]\nfn App() -> Html {\n    let on_name_entry: Callback<String> = Callback::from(move |name: String| {\n        let greeting = format!(\"Hey, {}!\", name);\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! { <HelloWorld {on_name_entry} /> }\n}\n\n```\n\n## DOM Events and Callbacks\n\nCallbacks are also used to hook into DOM events.\n\nFor example, here we define a callback that will be called when the user clicks the button:\n\n```rust\nuse yew::{component, html, Html, Properties, Callback};\n\n#[component]\nfn App() -> Html {\n    let onclick = Callback::from(move |_| {\n        let greeting = String::from(\"Hi there\");\n        // web_sys::console::log_1(&greeting.into()); // if uncommented will print\n    });\n\n    html! {\n        <button {onclick}>{ \"Click\" }</button>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/children.mdx",
    "content": "---\ntitle: 'Children'\n---\n\n`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[component]\nfn App() -> Html {\n    html! {\n        // highlight-start\n        <HelloWorld>\n            <span>{\"Hey what is up ;)\"}</span>\n            <h1>{\"THE SKY\"}</h1>\n        </HelloWorld>\n        // highlight-end\n    }\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-next-line\n    pub children: Html, // the field name `children` is important!\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    html! {\n        <div class=\"very-stylized-container\">\n    // highlight-next-line\n            { props.children.clone() } // you can forward children like this\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/communication.mdx",
    "content": "---\ntitle: 'Communication between components'\n---\n\n## Parent to child messaging\n\nPass data as [props](./properties) that cause a re-render, this is the way to pass messages to children.\n\n## Child to parent messaging\n\nPass down a callback via props, that the child on an event can call. [Example](callbacks#passing-callbacks-as-props)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/generics.mdx",
    "content": "---\ntitle: 'Generic Components'\ndescription: 'The #[component] attribute'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `#[component]` attribute also works with generic functions for creating generic components.\n\n```rust\nuse std::fmt::Display;\nuse yew::{component, html, Properties, Html};\n\n#[derive(Properties, PartialEq)]\npub struct Props<T>\nwhere\n    T: PartialEq,\n{\n    data: T,\n}\n\n#[component]\npub fn MyGenericComponent<T>(props: &Props<T>) -> Html\nwhere\n    T: PartialEq + Clone + Into<Html>,\n{\n    html! {\n        <p>\n            { props.data.clone().into() }\n        </p>\n    }\n}\n\n// then can be used like this\nhtml! {\n    <MyGenericComponent<i32> data=123 />\n};\n\n// or\nhtml! {\n    <MyGenericComponent<String> data={\"foo\".to_string()} />\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/hooks/custom-hooks.mdx",
    "content": "---\ntitle: 'Custom Hooks'\n---\n\n## Defining custom Hooks\n\nThe stateful logic of a component can be extracted into reusable functions by creating custom Hooks.\n\nConsider that we wish to create an event listener that listens to an event on the `window`\nobject.\n\n```rust\nuse yew::prelude::*;\nuse gloo::events::EventListener;\nuse gloo::utils::window;\nuse std::mem::drop;\n\n\n#[component(ShowStorageChanged)]\npub fn show_storage_changed() -> Html {\n    let state_storage_changed = use_state(|| false);\n\n    {\n        let state_storage_changed = state_storage_changed.clone();\n        use_effect(|| {\n            let listener = EventListener::new(&window(), \"storage\", move |_| state_storage_changed.set(true));\n\n            move || { drop(listener); }\n        });\n    }\n\n    html! { <div>{\"Storage Event Fired: \"}{*state_storage_changed}</div> }\n}\n```\n\nThere's one problem with this code: the logic can't be reused by another component.\nIf we build another component that listens to a different event,\ninstead of copying the code, we can move the logic into a custom hook.\n\nWe'll start by creating a new function called `use_event`.\nThe `use_` prefix denotes that a function is a hook.\nThis function will take an event target, an event type, and a callback.\nAll hooks must be marked by `#[hook]` on their function definition.\n\n```rust\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse gloo::events::EventListener;\nuse yew::prelude::*;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(&Event) + 'static,\n{\n    todo!()\n}\n```\n\nThis simple hook can be created by composing built-in hooks. For this example, we'll use the\n`use_effect_with` hook, so an event listener can be recreated when the hook arguments change.\n\n```rust\nuse yew::prelude::*;\nuse web_sys::{Event, EventTarget};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse gloo::events::EventListener;\n\n#[hook]\npub fn use_event<E, F>(target: &EventTarget, event_type: E, callback: F)\nwhere\n    E: Into<Cow<'static, str>>,\n    F: Fn(Event) + 'static,\n{\n    #[derive(PartialEq, Clone)]\n    struct EventDependents {\n        target: EventTarget,\n        event_type: Cow<'static, str>,\n        callback: Callback<Event>,\n    }\n\n    let deps = EventDependents {\n        target: target.clone(),\n        event_type: event_type.into(),\n        callback: Callback::from(callback),\n    };\n\n    use_effect_with(\n        deps,\n        |deps| {\n            let EventDependents {\n                target,\n                event_type,\n                callback,\n            } = deps.clone();\n\n            let listener = EventListener::new(&target, event_type, move |e| {\n                callback.emit(e.clone());\n            });\n\n            move || {\n                drop(listener);\n            }\n        },\n    );\n}\n```\n\nAlthough this approach works in almost all cases, it can't be used to write primitive hooks like the pre-defined hooks we've been using already.\n\nView the docs on [docs.rs](https://docs.rs/yew) for documentation and `hooks` directory to see implementations of pre-defined hooks.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/hooks/introduction.mdx",
    "content": "---\ntitle: 'Hooks'\nslug: /concepts/function-components/hooks\n---\n\n## Hooks\n\nHooks are functions that let you store state and perform side effects.\n\nYew comes with a few pre-defined hooks. You can also create your own or discover many [community-made hooks](/community/awesome#hooks).\n\n## Rules of hooks\n\n1. A hook function name always has to start with `use_`\n2. Hooks can only be used in the following locations:\n    - Top-level of a function/hook.\n    - Blocks inside a function/hook, given it is not already branched.\n    - In the condition of a top-level `if` expression inside a function/hook.\n    - In the scrutinee of a top-level `match` expression inside a function/hook.\n3. Hooks must be called in the same order for every render. Returning early is only allowed when using [Suspense](../../suspense.mdx)\n\nThese rules are enforced by either compile-time or run-time errors.\n\n### Pre-defined Hooks\n\nYew comes with the following predefined Hooks:\n\n- `use_state`\n- `use_state_eq`\n- `use_memo`\n- `use_callback`\n- `use_ref`\n- `use_mut_ref`\n- `use_node_ref`\n- `use_reducer`\n- `use_reducer_eq`\n- `use_effect`\n- `use_effect_with`\n- `use_context`\n- `use_force_update`\n\nThe documentation for these hooks can be found in the [Yew API docs](https://yew-rs-api.web.app/next/yew/functional/)\n\n### Custom Hooks\n\nThere are cases where you want to define your own Hooks to encapsulate potentially stateful logic from a component into reusable functions.\nSee the [Defining custom hooks](concepts/function-components/hooks/custom-hooks.mdx#defining-custom-hooks) section for more information.\n\n## Further reading\n\n- The React documentation has a section on [React hooks](https://reactjs.org/docs/hooks-intro.html).\n  These are not the same as Yew's hooks, but the underlying concept is similar.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/introduction.mdx",
    "content": "---\ntitle: 'Function Components'\nslug: /concepts/function-components\n---\n\nLet's revisit this previous statement:\n\n> Yew centrally operates on the idea of keeping everything that a reusable piece of\n> UI may need in one place - rust files.\n\nWe will refine this statement, by introducing the concept that will define the logic and\npresentation behavior of an application: \"components\".\n\n## What are Components?\n\nComponents are the building blocks of Yew.\n\nThey:\n\n- Take arguments in form of [Props](./properties.mdx)\n- Can have their own state\n- Compute pieces of HTML visible to the user (DOM)\n\n## Two flavors of Yew Components\n\nYou are currently reading about function components - the recommended way to write components\nwhen starting with Yew and when writing simple presentation logic.\n\nThere is a more advanced, but less accessible, way to write components - [Struct components](advanced-topics/struct-components/introduction.mdx).\nThey allow very detailed control, though you will not need that level of detail most of the time.\n\n## Creating function components\n\nTo create a function component add the `#[component]` attribute to a function.\nBy convention, the function is named in PascalCase, like all components, to contrast its\nuse to normal html elements inside the `html!` macro.\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// Then somewhere else you can use the component inside `html!`\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n```\n\n## What happens to components\n\nWhen rendering, Yew will build a virtual tree of these components.\nIt will call the view function of each (function) component to compute a virtual version (VDOM) of the DOM\nthat you as the library user see as the `Html` type.\nFor the previous example, this would look like this:\n\n```xhtml\n<App>\n    <HelloWorld>\n        <p>\"Hello world\"</p>\n    </HelloWorld>\n</App>\n```\n\nWhen an update is necessary, Yew will again call the view function and reconcile the new virtual DOM with its\nprevious version and only propagate the new/changed/necessary parts to the actual DOM.\nThis is what we call **rendering**.\n\n:::note\n\nBehind the scenes, `Html` is just an alias for `VNode` - a virtual node.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/node-refs.mdx",
    "content": "---\ntitle: 'Node Refs'\ndescription: 'Out-of-band DOM access'\n---\n\nThe `ref` attribute can be used to attach the `NodeRef` to an HTML element. In callbacks,\nyou can then get the DOM `Element` that the ref is attached to. This can be used to make\nchanges to the DOM outside of the `view` lifecycle method, retrieve the value of an `<input>`\nand other direct interactions with the DOM via the javascript API.\n\nThis is useful for getting ahold of canvas elements, or scrolling to different sections of a page.\n\n:::caution\nDo not manually modify the DOM tree that is rendered by Yew. Treat the `NodeRef` as a read-only\naccess, if you are unsure.\n:::\n\n## Further Reading\n\n- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)\n- [`node_refs` example](https://github.com/yewstack/yew/tree/master/examples/node_refs)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/properties.mdx",
    "content": "---\ntitle: 'Properties'\ndescription: 'Parent to child communication'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n:::note\n\nProperties are often shortened as \"Props\".\n\n:::\n\nProperties are essentially component arguments that Yew can keep watch on.\n\nA type has to implement the `Properties` trait before it can be used as the properties of a component.\n\n## Reactivity\n\nYew checks if props have changed when reconciling the Virtual DOM during re-rendering, to know if nested components need to be re-rendered.\nThis way Yew can be considered a very reactive framework, as changes from the parent will always be propagated downward,\nand the view will never be out of sync with the data coming from props/state.\n\n:::tip\n\nIf you have not yet completed the [tutorial](../../tutorial), try it out and test this reactivity yourself!\n\n:::\n\n## Derive macro\n\nYew provides a derive macro to easily implement the `Properties` trait on structs.\n\nTypes for which you derive `Properties` must also implement `PartialEq` so Yew can do data comparison.\n\n```rust\nuse yew::Properties;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n```\n\n## Use in function components\n\nThe attribute `#[component]` allows to optionally receive Props in the function arguments. To supply them,\nthey are assigned via attributes in the `html!` macro.\n\n<Tabs>\n  <TabItem value=\"with-props\" label=\"With Props\">\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    html! { <>{\"Am I loading? - \"}{is_loading}</> }\n}\n\n// Then supply the prop\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n\n```\n\n  </TabItem>\n  <TabItem value=\"no-props\" label=\"No Props\">\n\n```rust\nuse yew::{component, html, Html};\n\n#[component]\nfn HelloWorld() -> Html {\n    html! { \"Hello world\" }\n}\n\n// No props to supply\n#[component]\nfn App() -> Html {\n    html! { <HelloWorld /> }\n}\n\n```\n\n  </TabItem>\n</Tabs>\n\n## Derive macro field attributes\n\nWhen deriving `Properties` all fields are required by default.\nThe following attributes allow you to give your props default values which will be used when the parent has not set them.\n\n:::tip\nAttributes aren't visible in Rustdoc generated documentation.\nThe doc strings of your properties should mention whether a prop is optional and if it has a special default value.\n:::\n\n<Tabs>\n  <TabItem value=\"prop_or_default\" label=\"#[prop_or_default]\">\n\nInitialize the prop value with the default value of the field's type using the `Default` trait.\n\n```rust\nuse yew::{component, html, Html, Properties};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    // highlight-start\n    #[prop_or_default]\n    // highlight-end\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(&Props { is_loading }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <HelloWorld /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <HelloWorld is_loading=true /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_value\" label=\"#[prop_or(value)]\">\n\nUse `value` to initialize the prop value. `value` can be any expression that returns the field's type.\nFor example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`. The expression\nis evaluated when the properties are constructed and no explicit value has been given.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name} </>}\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"prop_or_else_function\" label=\"#[prop_or_else(function)]\">\n\nCall `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.\nThe function is called when no explicit value has been given for that attribute.\n\n```rust\nuse yew::prelude::*;\n\nfn create_default_name() -> AttrValue {\n    AttrValue::Static(\"Bob\")\n}\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    // highlight-start\n    #[prop_or_else(create_default_name)]\n    // highlight-end\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n// Then use like this with default\n#[component]\nfn Case1() -> Html {\n    html! { <Hello /> }\n}\n// Or no override the default\n#[component]\nfn Case2() -> Html {\n    html! { <Hello name=\"Sam\" /> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## Memory/speed overhead of using Properties\n\nInternally properties are reference counted. This means that only a shared pointer is passed down the component tree for props.\nIt saves us from the cost of having to clone the entire props, which might be expensive.\n\n:::tip\nMake use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.\n:::\n\n## Props macro\n\nThe `yew::props!` macro allows you to build properties the same way the `html!` macro does it.\n\nThe macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`).\nThe type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).\n\n```rust\nuse yew::prelude::*;\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    #[prop_or_default]\n    pub is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Bob\"))]\n    pub name: AttrValue,\n}\n\n#[component]\nfn Hello(&Props { is_loading, ref name }: &Props) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{\"Hello \"}{name}</> }\n    }\n}\n\n#[component]\nfn App() -> Html {\n    // highlight-start\n    let pre_made_props = yew::props! {\n        Props {} // Notice we did not need to specify name prop\n    };\n    // highlight-end\n    html! { <Hello ..pre_made_props /> }\n}\n```\n\n## Automatically generate properties (yew-autoprops)\n\nIn order to streamline your development process, you can also use the macro\n`#[autoprops]` (from the crate `yew-autoprops`) that will automatically\ngenerate the `Properties` struct for you.\n\n```rust\nuse yew::prelude::*;\nuse yew_autoprops::autoprops;\n\n// the #[autoprops] macro must appear BEFORE #[component], the order matters\n#[autoprops]\n#[component]\nfn Greetings(\n    #[prop_or_default]\n    is_loading: bool,\n    #[prop_or(AttrValue::Static(\"Hello\"))]\n    message: &AttrValue,\n    #[prop_or(AttrValue::Static(\"World\"))]\n    name: &AttrValue,\n) -> Html {\n    if is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { <>{message}{\" \"}{name}</> }\n    }\n}\n\n// The properties struct \"GreetingsProps\" will be generated automatically.\n//\n// `is_loading` will be passed as value to the components while `message` and\n// `name` will use references because of the leading `&` in the definition.\n```\n\n## Evaluation Order\n\nProps are evaluated in the order they're specified, as shown by the following example:\n\n```rust\n#[derive(yew::Properties, PartialEq)]\nstruct Props { first: usize, second: usize, last: usize }\n\nlet mut g = 1..=3;\nlet props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() });\n\nassert_eq!(props.first, 1);\nassert_eq!(props.second, 2);\nassert_eq!(props.last, 3);\n```\n\n## Anti Patterns\n\nWhile almost any Rust type can be passed as properties, there are some anti-patterns that should be avoided.\nThese include, but are not limited to:\n\n1. Using `String` type instead of `AttrValue`. <br />\n   **Why is this bad?** `String` can be expensive to clone.\n   Cloning is often needed when the prop value is used with hooks and callbacks. `AttrValue` is either\n   a reference-counted string (`Rc<str>`) or a `&'static str`, thus very cheap to clone.<br />\n   **Note**: `AttrValue` internally is `IString` from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n2. Using interior mutability. <br />\n   **Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should\n   _generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when the state has changed)\n   so you may have to manually force a render. Like all things, it has its place. Use it with caution.\n3. Using `Vec<T>` type instead of `IArray<T>`. <br />\n   **Why is this bad?** `Vec<T>`, just like `String`, can also be expensive to clone. `IArray<T>` is either\n   a reference-counted slice (`Rc<[T]>`) or a `&'static [T]`, thus very cheap to clone.<br />\n   **Note**: `IArray` can be imported from [implicit-clone](https://crates.io/crates/implicit-clone)\n   See that crate to learn more.\n4. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue\n   or PR a fix to this documentation.\n\n## yew-autoprops\n\n[yew-autoprops](https://crates.io/crates/yew-autoprops) is an experimental package that allows one to create the Props struct on the fly out of the arguments of your function. Might be useful, if the properties struct is never reused.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/pure-components.mdx",
    "content": "---\ntitle: 'Pure Components'\n---\n\nA function component is considered [pure] when the returned `Html` is deterministically derived\nfrom its props when its view function does not mutate its state or has other side effects.\n\n[pure]: https://en.wikipedia.org/wiki/Pure_function\n\nThe example below is a pure component. For a given prop `is_loading` it will always result in the same `Html` without any side effects.\n\n```rust\nuse yew::{Properties, component, Html, html};\n\n#[derive(Properties, PartialEq)]\npub struct Props {\n    pub is_loading: bool,\n}\n\n#[component]\nfn HelloWorld(props: &Props) -> Html {\n    if props.is_loading {\n        html! { \"Loading\" }\n    } else {\n        html! { \"Hello world\" }\n    }\n}\n```\n\n:::note\nIf you have an internal pure component that makes no use of hooks and other component machinery, you can often write it instead\nas a normal function returning `Html` and avoid a bit of overhead for Yew, related to running the component lifecycle. Use\n[expression syntax](concepts/html/literals-and-expressions.mdx#expressions) to render them in `html!`.\n:::\n\n## Impure components\n\nYou might wonder if a component can be impure if it does not use any globals, since it is just a function that is called every render.\nThis is where the next topic comes in - [hooks](./hooks)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/function-components/state.mdx",
    "content": "---\ntitle: 'State'\n---\n\n## General view of how to store state\n\nThis table can be used as a guide when deciding what state-storing type fits best for your use case:\n\n| Hook                     | Type                       | Rerender when?               | Scope               |\n| ------------------------ | -------------------------- | ---------------------------- | ------------------- |\n| [use_state]              | `T`                        | got set                      | component instance  |\n| [use_state_eq]           | `T: PartialEq`             | got set with diff. value     | component instance  |\n| [use_reducer]            | `T: Reducible`             | got reduced                  | component instance  |\n| [use_reducer_eq]         | `T: Reducible + PartialEq` | got reduced with diff. value | component instance  |\n| [use_memo]               | `Deps -> T`                | dependencies changed         | component instance  |\n| [use_callback]           | `Deps -> Callback<E>`      | dependencies changed         | component instance  |\n| [use_mut_ref]            | `T`                        | -                            | component instance  |\n| a static global variable | `T`                        | -                            | global, used by all |\n\n[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html\n[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html\n[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html\n[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html\n[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html\n[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html\n[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/classes.mdx",
    "content": "---\ntitle: 'Classes'\ndescription: 'A handy macro to handle classes'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Classes\n\nThe struct `Classes` can be used to deal with HTML classes.\n\nWhen pushing a string to the set, `Classes` ensures that there is one element\nfor every class even if a single string might contain multiple classes.\n\n`Classes` can also be merged by using `Extend` (i.e.\n`classes1.extend(classes2)`) or `push()` (i.e. `classes1.push(classes2)`).\nAny type that implements `Into<Classes>` can be pushed onto an existing `Classes`.\n\nThe macro `classes!` is a convenient macro that creates one single `Classes`.\nIts input accepts a comma-separated list of expressions. The only requirement\nis that every expression implements `Into<Classes>`.\n\n<Tabs>\n  <TabItem value=\"Literal\" label=\"Literal\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n    <div class={classes!(\"container\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Multiple\" label=\"Multiple\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(\"class-1\", \"class-2\")}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"String\" label=\"String\">\n\n```rust\nuse yew::{classes, html};\n\nlet my_classes = String::from(\"class-1 class-2\");\n\nhtml! {\n  <div class={classes!(my_classes)}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Optional\" label=\"Optional\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(Some(\"class\"))} />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Vector\" label=\"Vector\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!(vec![\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Array\" label=\"Array\">\n\n```rust\nuse yew::{classes, html};\n\nhtml! {\n  <div class={classes!([\"class-1\", \"class-2\"])}></div>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Components that accept classes\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    #[prop_or_default]\n    class: Classes,\n    fill: bool,\n    children: Html,\n}\n\n#[component]\nfn MyComponent(props: &Props) -> Html {\n    let Props {\n        class,\n        fill,\n        children,\n    } = props;\n    html! {\n        <div\n            class={classes!(\n                \"my-container-class\",\n                fill.then(|| Some(\"my-fill-class\")),\n                class.clone(),\n            )}\n        >\n            { children.clone() }\n        </div>\n    }\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/components.mdx",
    "content": "---\ntitle: 'Components'\ndescription: 'Create complex layouts with component hierarchies'\n---\n\n## Basic\n\nComponents can be used in the `html!` macro:\n\n```rust\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    html! {\n        { \"This component has no properties!\" }\n    }\n}\n\n#[derive(Clone, PartialEq, Properties)]\nstruct Props {\n    user_first_name: String,\n    user_last_name: String,\n}\n\n#[component]\nfn MyComponentWithProps(props: &Props) -> Html {\n    let Props { user_first_name, user_last_name } = props;\n    html! {\n        <>{\"user_first_name: \"}{user_first_name}{\" and user_last_name: \"}{user_last_name}</>\n    }\n}\n\nlet props = Props {\n    user_first_name: \"Bob\".to_owned(),\n    user_last_name: \"Smith\".to_owned(),\n};\n\nhtml!{\n    <>\n        // No properties\n        <MyComponent />\n\n        // With Properties\n        <MyComponentWithProps user_first_name=\"Sam\" user_last_name=\"Idle\" />\n\n        // With the whole set of props provided at once\n        <MyComponentWithProps ..props.clone() />\n\n        // With Properties from a variable and specific values overridden\n        <MyComponentWithProps user_last_name=\"Elm\" ..props />\n    </>\n};\n```\n\n## Nested\n\nComponents can accept child components/elements if they have a `children` field in their `Properties`\n\n```rust title=\"parent.rs\"\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nhtml! {\n    <Container id=\"container\">\n        <h4>{ \"Hi\" }</h4>\n        <div>{ \"Hello\" }</div>\n    </Container>\n};\n```\n\nThe `html!` macro allows you to pass a base expression with the `..props` syntax instead of specifying each property individually,\nsimilar to Rust's [Functional Update Syntax](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax).\nThis base expression must occur after any individual props are passed.\nWhen passing a base props expression with a `children` field, the children passed in the `html!` macro overwrite the ones already present in the props.\n\n```rust\nuse yew::prelude::*;\n\n#[derive(PartialEq, Properties)]\nstruct Props {\n    id: String,\n    children: Html,\n}\n\n#[component]\nfn Container(props: &Props) -> Html {\n    html! {\n        <div id={props.id.clone()}>\n            { props.children.clone() }\n        </div>\n    }\n}\n\nlet props = yew::props!(Props {\n    id: \"container-2\",\n    children: Html::default(),\n});\n\nhtml! {\n    <Container ..props>\n        // props.children will be overwritten with this\n        <span>{ \"I am a child, as you can see\" }</span>\n    </Container>\n};\n```\n\n## Relevant examples\n\n- [Function Todo MVC](https://github.com/yewstack/yew/tree/master/examples/function_todomvc)\n- [Function Router](https://github.com/yewstack/yew/tree/master/examples/function_router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/conditional-rendering.mdx",
    "content": "---\ntitle: 'Conditional rendering'\ndescription: 'Rendering nodes conditionally in html!'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## If blocks\n\nTo conditionally render some markup, we wrap it in an `if` block:\n\n<Tabs>\n  <TabItem value=\"if\" label=\"if\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    if true {\n        <p>{ \"True case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if - else\" label=\"if - else\">\n\n```rust\nuse yew::prelude::*;\nlet some_condition = true;\n\nhtml! {\n    if some_condition {\n        <p>{ \"True case\" }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let\" label=\"if let\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"if let else\" label=\"if let else\">\n\n```rust\nuse yew::prelude::*;\nlet some_text = Some(\"text\");\n\nhtml! {\n    if let Some(text) = some_text {\n        <p>{ text }</p>\n    } else {\n        <p>{ \"False case\" }</p>\n    }\n};\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/elements.mdx",
    "content": "---\ntitle: 'Elements'\ndescription: 'Both HTML and SVG elements are supported'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## DOM nodes\n\nThere are many reasons why you might want to create or manage DOM nodes manually in Yew, such as\nwhen integrating with JS libraries that can cause conflicts with managed components.\n\nUsing `web-sys`, you can create DOM elements and convert them into a `Node` - which can then be\nused as an `Html` value using `VRef`:\n\n```rust\nuse web_sys::{Element, Node};\nuse yew::prelude::*;\nuse gloo::utils::document;\n\n#[component]\nfn MyComponent() -> Html {\n    // memoize as this only needs to be executed once\n    let node = use_memo(\n        (),\n        |_| {\n            // Create a div element from the document\n            let div: Element = document().create_element(\"div\").unwrap();\n            // Add content, classes etc.\n            div.set_inner_html(\"Hello, World!\");\n            // Convert Element into a Node\n            let node: Node = div.into();\n            // Return that Node as a Html value\n            Html::VRef(node)\n        },\n    );\n\n    // use_memo return Rc so we need to deref and clone\n    (*node).clone()\n}\n\n```\n\n## Dynamic tag names\n\nWhen building a higher-order component you might find yourself in a situation where the element's tag name is not static.\nFor example, you might have a `Title` component that can render anything from `h1` to `h6` depending on a level prop.\nInstead of having to use a big match expression, Yew allows you to set the tag name dynamically\nusing `@{name}` where `name` can be any expression that returns a string.\n\n```rust\nuse yew::prelude::*;\n\nlet level = 5;\nlet text = \"Hello World!\".to_owned();\n\nhtml! {\n    <@{format!(\"h{}\", level)} class=\"title\">{ text }</@>\n};\n```\n\n## Boolean Attributes\n\nSome content attributes (e.g checked, hidden, required) are called boolean attributes. In Yew,\nboolean attributes need to be set to a bool value:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div hidden=true>\n        { \"This div is hidden.\" }\n    </div>\n};\n```\n\nThis will result in **HTML** that is functionally equivalent to this:\n\n```html\n<div hidden>This div is hidden.</div>\n```\n\nSetting a boolean attribute to false is equivalent to not using the attribute at all; values from\nboolean expressions can be used:\n\n```rust\nuse yew::prelude::*;\n\nlet no = 1 + 1 != 2;\n\nhtml! {\n    <div hidden={no}>\n        { \"This div is NOT hidden.\" }\n    </div>\n};\n```\n\nThis will result in the following **HTML**:\n\n```html\n<div>This div is NOT hidden.</div>\n```\n\n## String-like attributes\n\nBut apart from a select few boolean attributes, you will probably be dealing with a lot of string-like HTML attributes and Yew has a few options to pass string-like values to components.\n\n```rust\nuse yew::{html, virtual_dom::AttrValue};\n\nlet str_placeholder = \"I'm a str!\";\nlet string_placeholder = String::from(\"I'm a String!\");\nlet attrvalue_placeholder = AttrValue::from(\"I'm an AttrValue!\");\n\nhtml! {\n    <div>\n        <input placeholder={str_placeholder} />\n        <input placeholder={string_placeholder} />\n        <input placeholder={attrvalue_placeholder} />\n    </div>\n};\n```\n\nThey are all valid **but** we encourage you to favor Yew's custom `AttrValue`, especially if you need to clone or pass them as properties to another component.\n\n## Optional attributes for HTML elements\n\nMost HTML attributes can use optional values (Some(x) or None). This allows us to omit the attribute if the attribute is marked as optional.\n\n```rust\nuse yew::prelude::*;\n\nlet maybe_id = Some(\"foobar\");\n\nhtml! {\n    <div id={maybe_id}></div>\n};\n```\n\nIf the attribute is set to `None`, the attribute will not be set in the DOM.\n\n## Children\n\nMost HTML elements accept arbitrary HTML as children, however, there is a set of them that doesn't accept any children at all.\nThese elements are called _void_ elements, and they are:\n\n- `<area />`\n- `<base />`\n- `<base />`\n- `<br />`\n- `<col />`\n- `<embed />`\n- `<hr />`\n- `<img />`\n- `<input />`\n- `<link />`\n- `<meta />`\n- `<param />`\n- `<source />`\n- `<track />`\n- `<wbr />`\n- `<textarea />`\n\nAttempting to provide children to these elements will result in a compilation error or, if the element tag is chosen dynamically, in a panic.\n\n### The case of `<textarea>`\n\nThe `<textarea>` element is special; The modern HTML specification states that children of `<textarea>` define its default value, however in Yew it's specified differently.\nInstead of writing\n\n```html\n<textarea>{\"default value\"}</textarea>\n```\n\nWhich would fail to compile, it's customary to write\n\n```html\n<textarea defaultvalue=\"default value\" />\n```\n\n## Relevant examples\n\n- [Inner HTML](https://github.com/yewstack/yew/tree/master/examples/inner_html)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/events.mdx",
    "content": "---\ntitle: 'Events'\n---\n\n## Introduction\n\nYew integrates with the [`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/) crate and\nuses the events from that crate. The [table below](#event-types) lists all of the `web-sys`\nevents that are accepted in the `html!` macro.\n\nYou can still add a [`Callback`](../function-components/callbacks.mdx) for an event that is not listed in the table\nbelow, see [Manual event listener](#manual-event-listener).\n\n## Event Types\n\n:::tip\nAll the event types mentioned in the following table are re-exported under `yew::events`.\nUsing the types from `yew::events` makes it easier to ensure version compatibility than\nif you were to manually include `web-sys` as a dependency in your crate because you will not\nend up using a version which conflicts with the version that Yew specifies.\n:::\n\nThe event listener name is the expected name when adding an event `Callback` in the `html` macro:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <button onclick={Callback::from(|_| ())}>\n    //      ^^^^^^^ event listener name\n        { \"Click me!\" }\n    </button>\n};\n```\n\nThe event name is the listener without the \"on\" prefix, therefore, the `onclick` event listener\nlistens for `click` events. See the end of this page for a [full list of available event](#available-events) with their types.\n\n## Event bubbling {#event-bubbling}\n\nEvents dispatched by Yew follow the virtual DOM hierarchy when bubbling up to listeners. Currently, only the bubbling phase\nis supported for listeners. Note that the virtual DOM hierarchy is most often, but not always, identical to the actual\nDOM hierarchy. The distinction is important when working with [portals](../../advanced-topics/portals) and other\nmore advanced techniques. The intuition for well-implemented components should be that events bubble from children\nto parents. In this way the hierarchy in your coded `html!` is the one observed by event handlers.\n\nIf you are not interested in event bubbling, you can turn it off by calling\n\n```rust\nyew::set_event_bubbling(false);\n```\n\n_before_ starting your app. This speeds up event handling, but some components may break from not receiving the events they expect.\nUse this with care!\n\n## Event delegation\n\nIt can be surprising that event listeners are _not_ directly registered on the element where they are rendered. Instead, events\nare delegated from the subtree root of the Yew app. Still, events are delivered in their native form, and no synthetic\nform is created. This can lead to mismatches between the event you would expect in HTML listeners and those showing up in Yew.\n\n- [`Event::current_target`] points to the Yew subtree root instead of the element the listener is added on. Use\n  [`NodeRef`](../function-components/node-refs.mdx) if you want access to the underlying `HtmlElement`.\n- [`Event::event_phase`] is always [`Event::CAPTURING_PHASE`]. Internally, the event will behave as if it was in the bubbling\n  phase, the event propagation is replayed and the event [bubbles _up_](#event-bubbling), i.e. event listeners higher up in\n  the virtual DOM will trigger _after_ event listeners below them. Currently, capturing listeners is not supported by Yew.\n\n    This also means that events registered by Yew will usually fire before other event listeners.\n\n[`event::current_target`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.current_target\n[`event::event_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.event_phase\n[`event::capturing_phase`]: https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#associatedconstant.CAPTURING_PHASE\n\n## Typed event target\n\n:::caution\nIn this section **target ([`Event.target`](https://developer.mozilla.org/en-US/docs/Web/API/Event/target))**\nis always referring to the element at which the event was dispatched from.\n\nThis will **not** always be the element at which the `Callback` is placed.\n:::\n\nIn event `Callback`s you may want to get the target of that event. For example, the\n`change` event gives no information but is used to notify that something has changed.\n\nIn Yew getting the target element in the correct type can be done in a few ways and we will go through\nthem here. Calling [`web_sys::Event::target`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target)\non an event returns an optional [`web_sys::EventTarget`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.EventTarget.html)\ntype, which might not seem very useful when you want to know the value of your input element.\n\nIn all the approaches below we are going to tackle the same problem, so it is clear where the approach\ndiffers as opposed to the problem at hand.\n\n**The Problem:**\n\nWe have an `onchange` `Callback` on my `<input>` element and each time it is invoked we want to send\nan [update](components#update) `Msg` to our component.\n\nOur `Msg` enum looks like this:\n\n```rust\npub enum Msg {\n    InputValue(String),\n}\n```\n\n### Using `JsCast`\n\nThe [`wasm-bindgen`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) crate has\na useful trait: [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html),\nwhich allows us to hop and skip our way to the type we want, as long as it implements `JsCast`. We can\ndo this cautiously, which involves some runtime checks and failure types like `Option` and `Result`,\nor we can do it dangerously.\n\nEnough talk, more code:\n\n```toml title=\"Cargo.toml\"\n[dependencies]\n# need wasm-bindgen for JsCast\nwasm-bindgen = \"0.2\"\n```\n\n```rust\n//highlight-next-line\nuse wasm_bindgen::JsCast;\nuse web_sys::{EventTarget, HtmlInputElement};\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            // When events are created the target is undefined, it's only\n            // when dispatched does the target get added.\n            let target: Option<EventTarget> = e.target();\n            // Events can bubble so this listener might catch events from child\n            // elements which are not of type HtmlInputElement\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        // Here we are sure that this is input element so we can convert it to the appropriate type without checking\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nThe methods from `JsCast` are [`dyn_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into)\nand [`unchecked_into`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.unchecked_into)\nand you can probably see, they allowed\nus to go from `EventTarget` to [`HtmlInputElement`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.HtmlInputElement.html).\nThe `dyn_into` method is cautious because at\nruntime it will check whether the type is actually a `HtmlInputElement` and if not return an\n`Err(JsValue)`, the [`JsValue`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)\nis a catch-all type and is essentially giving you back the object to try again.\n\nAt this point you might be thinking... when is the dangerous version ok to use? In the case above it\nis safe<sup>1</sup> as we've set the `Callback` on to an element with no children so the target can\nonly be that same element.\n\n_<sup>1</sup> As safe as anything can be when JS land is involved._\n\n### Using `TargetCast`\n\n**It is highly recommended to read [Using JsCast](#using-jscast) first!**\n\n:::note\n`TargetCast` was designed to feel very similar to `JsCast` - this is to allow new users to get a feel\nfor the behaviour of `JsCast` but with the smaller scope of events and their targets.\n\n`TargetCast` vs `JsCast` is purely preference, you will find that `TargetCast` implements something\nsimilar to what you would using `JsCast`.\n:::\n\nThe `TargetCast` trait is built on top of `JsCast` and is specialized towards getting typed event\ntargets from events.\n\n`TargetCast` comes with Yew so no need to add a dependency in order to use the trait methods on events\nbut it works in a very similar way to `JsCast`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let on_cautious_change = {\n        let input_value_handle = input_value_handle.clone();\n\n        Callback::from(move |e: Event| {\n            let input = e.target_dyn_into::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        //highlight-next-line\n        input_value_handle.set(e.target_unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">\n                { \"My dangerous input:\" }\n                <input onchange={on_dangerous_change}\n                    id=\"dangerous-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nIf you followed the advice above and read about `JsCast`, or know the trait, you can probably\nsee that `TargetCast::target_dyn_into` feels similar to `JsCast::dyn_into` but specifically\ndoes the cast on the target of the event. `TargetCast::target_unchecked_into` is similar to\n`JsCast::unchecked_into`, and as such all the same warnings above `JsCast` apply to `TargetCast`.\n\n### Using `NodeRef`\n\n[`NodeRef`](../function-components/node-refs.mdx) can be used instead of querying the event given to a `Callback`.\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    //highlight-next-line\n    let input_node_ref = use_node_ref();\n\n    let input_value_handle = use_state(String::default);\n    let input_value = (*input_value_handle).clone();\n\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            //highlight-next-line\n            let input = input_node_ref.cast::<HtmlInputElement>();\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                //highlight-next-line\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                    value={input_value}\n                />\n            </label>\n        </>\n    }\n}\n```\n\nUsing `NodeRef`, you can ignore the event and use the `NodeRef::cast` method to get an\n`Option<HtmlInputElement>` - this is optional as calling `cast` before the `NodeRef` has been\nset, or when the type doesn't match will return `None`.\n\nYou might also see by using `NodeRef` we don't have to send the `String` back into state as we always access to `input_node_ref` - so we could do the following:\n\n```rust\nuse web_sys::HtmlInputElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let input_node_ref = use_node_ref();\n\n    //highlight-start\n    let onchange = {\n        let input_node_ref = input_node_ref.clone();\n\n        Callback::from(move |_| {\n            if let Some(input) = input_node_ref.cast::<HtmlInputElement>() {\n                let value = input.value();\n                // do something with value\n            }\n        })\n    };\n    //highlight-end\n\n    html! {\n        <>\n            <label for=\"my-input\">\n                { \"My input:\" }\n                <input ref={input_node_ref}\n                    {onchange}\n                    id=\"my-input\"\n                    type=\"text\"\n                />\n            </label>\n        </>\n    }\n}\n```\n\nWhich approach you take depends on your component and your preferences, there is no _blessed_ way\nper se.\n\n## Manual event listener\n\nYou may want to listen to an event that is not supported by Yew's `html` macro, see the\n[supported events listed here](#event-types).\n\nIn order to add an event listener to one of elements manually we need the help of\n[`NodeRef`](../function-components/node-refs.mdx) so that in `use_effect_with` we can add a listener using the\n[`web-sys`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/index.html) and\n[wasm-bindgen](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/index.html) API.\n\nThe examples below are going to show adding listeners for the made-up `custard` event. All events\neither unsupported by yew or custom can be represented as a\n[`web_sys::Event`](https://wasm-bindgen.github.io/wasm-bindgen/api/web_sys/struct.Event.html). If you\nneed to access a specific method or field on a custom / unsupported event then you can use the\nmethods of [`JsCast`](https://wasm-bindgen.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)\nin order to convert to the type required.\n\n### Using `Closure` (verbose)\n\nUsing the `web-sys` and `wasm-bindgen` API's directly for this can be a bit painful.. so brace\nyourself ([there is a more concise way thanks to `gloo`](#using-gloo-concise)).\n\n```rust\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener =\n                        Closure::<dyn Fn(Event)>::wrap(\n                            Box::new(move |e: Event| oncustard.emit(e))\n                        );\n\n                    element\n                        .add_event_listener_with_callback(\n                            \"custard\",\n                            listener.as_ref().unchecked_ref()\n                        )\n                        .unwrap();\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `Closures`, see\n[The `wasm-bindgen` Guide](https://wasm-bindgen.github.io/wasm-bindgen/examples/closures.html).\n\n### Using `gloo` (concise)\n\nThe easier way is with `gloo`, more specifically [`gloo_events`](https://docs.rs/gloo-events/0.1.1/gloo_events/index.html)\nwhich is an abstraction for `web-sys`, `wasm-bindgen`.\n\n`gloo_events` has the `EventListener` type which can be used to create and store the\nevent listener.\n\n```toml title=\"Cargo.toml\"\n[dependencies]\ngloo-events = \"0.1\"\n```\n\n```rust\nuse web_sys::HtmlElement;\nuse yew::prelude::*;\n\nuse gloo::events::EventListener;\n\n#[component]\nfn MyComponent() -> Html {\n    let div_node_ref = use_node_ref();\n\n    use_effect_with(\n        div_node_ref.clone(),\n        {\n            let div_node_ref = div_node_ref.clone();\n\n            move |_| {\n                let mut custard_listener = None;\n\n                if let Some(element) = div_node_ref.cast::<HtmlElement>() {\n                    // Create your Callback as you normally would\n                    let oncustard = Callback::from(move |_: Event| {\n                        // do something about custard..\n                    });\n\n                    // Create a Closure from a Box<dyn Fn> - this has to be 'static\n                    let listener = EventListener::new(\n                        &element,\n                        \"custard\",\n                        move |e| oncustard.emit(e.clone())\n                    );\n\n                    custard_listener = Some(listener);\n                }\n\n                move || drop(custard_listener)\n            }\n        }\n    );\n\n    html! {\n        <div ref={div_node_ref} id=\"my-div\"></div>\n    }\n}\n```\n\nFor more information on `EventListener`, see the\n[gloo_events docs.rs](https://docs.rs/gloo-events/0.1.1/gloo_events/struct.EventListener.html).\n\n## Full list of available events {#available-events}\n\n| Event listener name         | `web_sys` Event Type                                                                  |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `onabort`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onauxclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onblur`                    | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `oncancel`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplay`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncanplaythrough`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onchange`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onclick`                   | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onclose`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncontextmenu`             | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `oncuechange`               | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ondblclick`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `ondrag`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragend`                 | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragenter`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragexit`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragleave`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragover`                | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondragstart`               | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondrop`                    | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html)             |\n| `ondurationchange`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onemptied`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onended`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onerror`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onfocus`                   | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusin`                 | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onfocusout`                | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html)           |\n| `onformdata`                | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oninput`                   | [InputEvent](https://docs.rs/web-sys/latest/web_sys/struct.InputEvent.html)           |\n| `oninvalid`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onkeydown`                 | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeypress`                | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onkeyup`                   | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html)     |\n| `onload`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadeddata`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadedmetadata`          | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onloadstart`               | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onmousedown`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseenter`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseleave`              | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmousemove`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseout`                | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseover`               | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onmouseup`                 | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html)           |\n| `onpause`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplay`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onplaying`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onprogress`                | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onratechange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onreset`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onresize`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onscroll`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeked`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onseeking`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselect`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onslotchange`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onstalled`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onsubmit`                  | [SubmitEvent](https://docs.rs/web-sys/latest/web_sys/struct.SubmitEvent.html)         |\n| `onsuspend`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontimeupdate`              | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontoggle`                  | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onvolumechange`            | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwaiting`                 | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onwheel`                   | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html)           |\n| `oncopy`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `oncut`                     | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpaste`                   | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onanimationcancel`         | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationend`            | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationiteration`      | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `onanimationstart`          | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html)   |\n| `ongotpointercapture`       | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onloadend`                 | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html)     |\n| `onlostpointercapture`      | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointercancel`           | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerdown`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerenter`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerleave`            | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerlockchange`       | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointerlockerror`        | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onpointermove`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerout`              | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerover`             | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onpointerup`               | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html)       |\n| `onselectionchange`         | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onselectstart`             | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `onshow`                    | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html)                     |\n| `ontouchcancel`             | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchend`                | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchmove`               | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontouchstart`              | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html)           |\n| `ontransitioncancel`        | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionend`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionrun`           | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n| `ontransitionstart`         | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) |\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/fragments.mdx",
    "content": "---\ntitle: 'Fragments'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro always requires a single root node. To get around this restriction, you\ncan use an \"empty tag\" (these are also called \"fragments\").\n\n<Tabs>\n<TabItem value=\"Valid\" label=\"Valid\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <>\n        <div></div>\n        <p></p>\n    </>\n};\n\n```\n\n</TabItem>\n\n<TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust, compile_fail\nuse yew::prelude::*;\n\n// error: only one root html element allowed\n\nhtml! {\n    <div></div>\n    <p></p>\n};\n\n```\n\n</TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/introduction.mdx",
    "content": "---\ntitle: 'HTML'\nsidebar_label: Introduction\ndescription: 'The procedural macro for generating HTML and SVG'\nslug: /concepts/html\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\nThe `html!` macro allows you to write HTML and SVG code declaratively. It is similar to JSX\n(an extension to JavaScript that allows you to write HTML-like code inside of JavaScript).\n\n**Important notes**\n\n1. The `html!` macro only accepts one root html node (you can counteract this by using\n   [fragments](./fragments.mdx) or [iterators](./../html/lists.mdx))\n2. An empty `html! {}` invocation is valid and will not render anything\n3. Literals must always be quoted and wrapped in braces: `html! { <p>{ \"Hello, World\" }</p> }`\n4. The `html!` macro will make all tag names lowercase. To use upper case characters (which are required for some SVG elements) use [dynamic tag names](concepts/html/elements.mdx#dynamic-tag-names): `html! { <@{\"myTag\"}></@> }`\n\n:::note\nThe `html!` macro can reach the default recursion limit of the compiler. If you encounter compilation errors,\nadd an attribute like `#![recursion_limit=\"1024\"]` in the crate root to overcome the problem.\n:::\n\n## Tag Structure\n\nTags are based on HTML tags. Components, Elements, and Lists are all based on this tag syntax.\n\nTags must either self-close `<... />` or have a corresponding end tag for each start tag.\n\n<Tabs>\n  <TabItem value=\"Open - Close\" label=\"Open - Close\" default>\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"></div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <div id=\"my_div\"> // <- MISSING CLOSE TAG\n};\n```\n\n  </TabItem>\n</Tabs>\n\n<Tabs>\n  <TabItem value=\"Self-closing\" label=\"Self-closing\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\" />\n};\n```\n\n  </TabItem>\n  <TabItem value=\"Invalid\" label=\"Invalid\">\n\n```rust ,compile_fail\nuse yew::prelude::*;\n\nhtml! {\n  <input id=\"my_input\"> // <- MISSING SELF-CLOSE\n};\n```\n\n  </TabItem>\n</Tabs>\n\n:::tip\nFor convenience, elements which _usually_ require a closing tag are **allowed** to self-close. For example, writing `html! { <div class=\"placeholder\" /> }` is valid.\n:::\n\n## Children\n\nCreate complex nested HTML and SVG layouts with ease:\n\n<Tabs>\n  <TabItem value=\"HTML\" label=\"HTML\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <div>\n        <div data-key=\"abc\"></div>\n        <div class=\"parent\">\n            <span class=\"child\" value=\"anything\"></span>\n            <label for=\"first-name\">{ \"First Name\" }</label>\n            <input type=\"text\" id=\"first-name\" value=\"placeholder\" />\n            <input type=\"checkbox\" checked=true />\n            <textarea value=\"write a story\" />\n            <select name=\"status\">\n                <option selected=true disabled=false value=\"\">{ \"Selected\" }</option>\n                <option selected=false disabled=true value=\"\">{ \"Unselected\" }</option>\n            </select>\n        </div>\n    </div>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"SVG\" label=\"SVG\">\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    <svg width=\"149\" height=\"147\" viewBox=\"0 0 149 147\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path d=\"M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z\" fill=\"#DEB819\"/>\n        <path d=\"M108.361 94.9937L138.708 90.686L115.342 69.8642\" stroke=\"black\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <g filter=\"url(#filter0_d)\">\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"55\" fill=\"#FDD630\"/>\n            <circle cx=\"75.3326\" cy=\"73.4918\" r=\"52.5\" stroke=\"black\" stroke-width=\"5\"/>\n        </g>\n        <circle cx=\"71\" cy=\"99\" r=\"5\" fill=\"white\" fill-opacity=\"0.75\" stroke=\"black\" stroke-width=\"3\"/>\n        <defs>\n            <filter id=\"filter0_d\" x=\"16.3326\" y=\"18.4918\" width=\"118\" height=\"118\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n                <@{\"feGaussianBlur\"} stdDeviation=\"2\"/>\n                <@{\"feColorMatrix\"} in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"/>\n            </filter>\n        </defs>\n    </svg>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Lints\n\nIf you compile Yew using a nightly version of the Rust compiler, the macro will warn you about some\ncommon pitfalls that you might run into. Of course, you may need to use the stable compiler (e.g.\nyour organization might have a policy mandating it) for release builds, but even if you're using a\nstable toolchain, running `cargo +nightly check` might flag some ways that you could improve your\nHTML code.\n\nAt the moment the lints are mostly accessibility-related. If you have ideas for lints, please feel\nfree to [chime in on this issue](https://github.com/yewstack/yew/issues/1334).\n\n## Specifying attributes and properties\n\nAttributes are set on elements in the same way as in normal HTML:\n\n```rust\nuse yew::prelude::*;\n\nlet value = \"something\";\nhtml! { <div attribute={value} /> };\n```\n\nProperties are specified with `~` before the element name:\n\n```rust , ignore\nuse yew::prelude::*;\n\nhtml! { <my-element ~property=\"abc\" /> };\n```\n\n:::tip\n\nThe braces around the value can be omitted if the value is a literal.\n\n:::\n\n:::note What classifies as a literal\n\nLiterals are all valid [literal expressions](https://doc.rust-lang.org/reference/expressions/literal-expr.html)\nin Rust. Note that [negative numbers are **not** literals](https://users.rust-lang.org/t/why-are-negative-value-literals-expressions/43333)\nand thus must be enclosed in curly-braces `{-6}`\n\n:::\n\n:::note Component properties\nComponent properties are passed as Rust objects and are different from the element attributes/properties described here.\nRead more about them at [Component Properties](../function-components/properties.mdx)\n:::\n\n### Special properties\n\nThere are special properties which don't directly influence the DOM but instead act as instructions to Yew's virtual DOM.\nCurrently, there are two such special props: `ref` and `key`.\n\n`ref` allows you to access and manipulate the underlying DOM node directly. See [Refs](../function-components/node-refs.mdx) for more details.\n\n`key` on the other hand gives an element a unique identifier which Yew can use for optimization purposes.\n\n:::info\nRead more at [Lists](./html/lists)\n:::\n\n## Comments\n\nIt is also possible to use Rust style comments as part of the HTML structure:\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  <>\n    <h1>{ \"My heading\" }</h1>\n    // here comes the content\n    <main>\n      { \"…\" }\n    </main>\n  </>\n};\n```\n\nComments will be dropped during the parsing process and will not end up in the final output.\n\n## Conditional Rendering\n\nMarkup can be rendered conditionally by using Rust's conditional structures. ' +\n'Currently only `if` and `if let` are supported.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n  if true {\n      <p>{ \"True case\" }</p>\n  }\n};\n```\n\n:::info\nRead more at [Conditional Rendering](./conditional-rendering.mdx)\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/lists.mdx",
    "content": "---\ntitle: 'Lists'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Iterators\n\nThere are 3 ways to build HTML from iterators:\n\n<Tabs>\n  <TabItem value=\"`for` loops\" label=\"`for` loops\">\nThe main approach is to use for loops, the same for loops that already exist in Rust, but with 2 key differences:\n1. Unlike standard for loops which can't return anything, for loops in `html!` are converted to a list of nodes;\n2. Diverging expressions, i.e. `break`, `continue` are not allowed in the body of for loops in `html!`.\n\n```rust\nuse yew::prelude::*;\n\nhtml! {\n    for i in 0 .. 10 {\n        <span>{i}</span>\n    }\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`for` block\" label=\"`for` block\">\nAn alternative is to use the `for` keyword, which is not native Rust syntax and instead is used by\nthe HTML macro to output the needed code to display the iterator.\nThis approach is better than the first one when the iterator is already computed and the only thing left to do\nis to pass it to the macro.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { for items.iter() }\n    </ul>\n};\n```\n\n  </TabItem>\n  <TabItem value=\"`collect` method\" label=\"`collect` method\">\n\nThe last is to call `collect::<Html>()` on the final transform in your iterator, which returns a\nlist that Yew can display.\n\n```rust\nuse yew::prelude::*;\n\nlet items = (1..=10).collect::<Vec<_>>();\n\nhtml! {\n    <ul class=\"item-list\">\n        { items.iter().collect::<Html>() }\n    </ul>\n};\n```\n\n  </TabItem>\n</Tabs>\n\n## Keyed lists\n\nA keyed list is an optimized list that has keys on **all** children.\n`key` is a special prop provided by Yew that gives an HTML element or component a unique identifier\nthat is used for optimization purposes inside Yew.\n\n:::caution\nKey has to be unique only in each list, in contrast to the global uniqueness of HTML `id`s. It must not depend on the order of the list.\n:::\n\nIt is always recommended to add keys to lists.\n\nKeys can be added by passing a unique `String`, `str` or integer to the special `key` prop:\n\n```rust , ignore\nuse yew::prelude::*;\n\nlet names = vec![\"Sam\",\"Bob\",\"Ray\"]\n\nhtml! {\n    <div id=\"introductions\">\n        {\n            names.into_iter().map(|name| {\n                html!{<div key={name}>{ format!(\"Hello, I'am {}!\",name) }</div>}\n            }).collect::<Html>()\n        }\n    </div>\n};\n\n```\n\n### Performance increases\n\nWe have [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list) example that lets you test the performance improvements, but here is a rough rundown:\n\n1. Go to [Keyed list hosted demo](https://examples.yew.rs/keyed_list)\n2. Add 500 elements.\n3. Disable keys.\n4. Reverse the list.\n5. Look at \"The last rendering took Xms\" (At the time of writing this it was ~60ms)\n6. Enable keys.\n7. Reverse the list.\n8. Look at \"The last rendering took Xms\" (At the time of writing this it was ~30ms)\n\nSo just at the time of writing this, for 500 components it is a 2x increase of speed.\n\n### Detailed explanation\n\nUsually, you just need a key on every list item when you iterate and the order of data can change.\nIt's used to speed up the reconciliation process when re-rendering the list.\n\nWithout keys, assume you iterate through `[\"bob\", \"sam\", \"rob\"]`, ending up with the HTML:\n\n```html\n<div id=\"bob\">My name is Bob</div>\n<div id=\"sam\">My name is Sam</div>\n<div id=\"rob\">My name is rob</div>\n```\n\nThen on the next render, if your list changed to `[\"bob\", \"rob\"]`, yew could delete\nthe element with id=\"rob\" and update id=\"sam\" to be id=\"rob\"\n\nIf you had added a key to each element, the initial HTML would be the same, but after\nthe render with the modified list, `[\"bob\", \"rob\"]`, yew would just delete the second\nHTML element and leave the rest untouched since it can use the keys to associate them.\n\nIf you ever encounter a bug/\"feature\" where you switch from one component to another but both have a div as the highest rendered element.\nYew reuses the rendered HTML div in those cases as an optimization.\nIf you need that div to be recreated instead of reused, then you can add different keys and they will not be reused.\n\n## Further reading\n\n- [TodoMVC](https://github.com/yewstack/yew/tree/master/examples/todomvc)\n- [Keyed list](https://github.com/yewstack/yew/tree/master/examples/keyed_list)\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/html/literals-and-expressions.mdx",
    "content": "---\ntitle: 'Literals and Expressions'\n---\n\n## Literals\n\nIf expressions resolve to types that implement `Display`, they will be converted to strings and inserted into the DOM as a [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) node.\n:::note\nString literals create `Text` nodes, which are treated as strings by the browser. Hence, even if the expression contains a `<script>` tag you can't fall for XSS and such security issues, unless of course you wrap the expression in a `<script>` block.\n:::\n\nAll display text must be enclosed by `{}` blocks because the text is handled as an expression. This is\nthe largest deviation from normal HTML syntax that Yew makes.\n\n```rust\nuse yew::prelude::*;\n\nlet text = \"lorem ipsum\";\nhtml!{\n    <>\n        <div>{text}</div>\n        <div>{\"dolor sit\"}</div>\n        <span>{42}</span>\n    </>\n};\n```\n\n## Expressions\n\nYou can insert expressions in your HTML using `{}` blocks, as long as they resolve to `Html`\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\n\nhtml! {\n  <div>\n    {\n      if show_link {\n        html! {\n          <a href=\"https://example.com\">{\"Link\"}</a>\n        }\n      } else {\n        html! {}\n      }\n    }\n  </div>\n};\n```\n\nIt often makes sense to extract these expressions into functions or closures to optimize for readability:\n\n```rust\nuse yew::prelude::*;\n\nlet show_link = true;\nlet maybe_display_link = move || -> Html {\n  if show_link {\n    html! {\n      <a href=\"https://example.com\">{\"Link\"}</a>\n    }\n  } else {\n    html! {}\n  }\n};\n\nhtml! {\n     <div>{maybe_display_link()}</div>\n};\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/router.mdx",
    "content": "---\ntitle: 'Router'\ndescription: \"Yew's official router\"\n---\n\nRouters in Single Page Applications (SPA) handle displaying different pages depending on what the URL is. Instead of the\ndefault behavior of requesting a different remote resource when a link is clicked, the router instead sets the URL\nlocally to point to a valid route in your application. The router then detects this change and then decides what to\nrender.\n\nYew provides router support in the `yew-router` crate. To start using it, add the dependency to your `Cargo.toml`:\n\n```sh\ncargo add yew-router\n```\n\nThe utilities needed are provided under `yew_router::prelude`,\n\n## Usage\n\nYou start by defining a `Route`.\n\nRoutes are defined as an `enum` which derives `Routable`. This enum must be `Clone + PartialEq`.\n\n```rust\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n```\n\nA `Route` is paired with a `<Switch />` component, which finds the variant whose path matches the browser's\ncurrent URL and passes it to the `render` callback. The callback then decides what to render. In case no path is\nmatched, the router navigates to the path with `not_found` attribute. If no route is specified, nothing is rendered, and\na message is logged to the console stating that no route was matched.\n\nMost of yew-router's components, in particular `<Link />` and `<Switch />`, must be (grand-)children of one of the Router components\n(e.g. `<BrowserRouter />`). You usually only need a single Router in your app, most often rendered immediately by your most top-level `<App />`\ncomponent. The Router registers a context, which is needed for Links and Switches to function. An example is shown below.\n\n:::caution\nWhen using `yew-router` in a browser environment, `<BrowserRouter />` is highly recommended.\nYou can find other router flavors in the [API Reference](https://docs.rs/yew-router/).\n:::\n\n```rust\nuse yew_router::prelude::*;\nuse yew::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/secure\")]\n    Secure,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[component(Secure)]\nfn secure() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n    html! {\n        <div>\n            <h1>{ \"Secure\" }</h1>\n            <button {onclick}>{ \"Go Home\" }</button>\n        </div>\n    }\n}\n\nfn switch(routes: Route) -> Html {\n    match routes {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Secure => html! {\n            <Secure />\n        },\n        Route::NotFound => html! { <h1>{ \"404\" }</h1> },\n    }\n}\n\n#[component(Main)]\nfn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<Route> render={switch} /> // <- must be child of <BrowserRouter>\n        </BrowserRouter>\n    }\n}\n```\n\n### Path Segments\n\nIt is also possible to extract information from a route using dynamic and named wildcard segments.\nYou can then access the post's id inside `<Switch />` and forward it to the appropriate component via properties.\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/post/:id\")]\n    Post { id: String },\n    #[at(\"/*path\")]\n    Misc { path: String },\n}\n\nfn switch(route: Route) -> Html {\n    match route {\n        Route::Home => html! { <h1>{ \"Home\" }</h1> },\n        Route::Post { id } => html! {<p>{format!(\"You are looking at Post {}\", id)}</p>},\n        Route::Misc { path } => html! {<p>{format!(\"Matched some other path: {}\", path)}</p>},\n    }\n}\n```\n\n:::note\nYou can have a normal `Post` variant instead of `Post {id: String}` too. For example, when `Post` is rendered\nwith another router, the field can then be redundant as the other router can match and handle the path. See the\n[Nested Router](#nested-router) section below for details\n:::\n\nNote the fields must implement `Clone + PartialEq` as part of the `Route` enum. They must also implement\n`std::fmt::Display` and `std::str::FromStr` for serialization and deserialization. Primitive types like integer, float,\nand String already satisfy the requirements.\n\nIn case when the form of the path matches, but the deserialization fails (as per `FromStr`). The router will consider\nthe route as unmatched and try to render the not found route (or a blank page if the not found route is unspecified).\n\nConsider this example:\n\n```rust ,ignore\n#[derive(Clone, Routable, PartialEq)]\nenum Route {\n    #[at(\"/news/:id\")]\n    News { id: u8 },\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n// switch function renders News and id as is. Omitted here.\n```\n\nWhen the segment goes over 255, `u8::from_str()` fails with `ParseIntError`, the router will then consider the route\nunmatched.\n\n![router deserialization failure behavior](/img/router-deserialization-failure-behavior.gif)\n\nFor more information about the route syntax and how to bind parameters, check\nout [route-recognizer](https://docs.rs/route-recognizer/0.3.1/route_recognizer/#routing-params).\n\n### Location\n\nThe router provides a universal `Location` struct via context which can be used to access routing information.\nThey can be retrieved by hooks or convenient functions on `ctx.link()`.\n\n### Navigation\n\n`yew_router` provides a handful of tools to work with navigation.\n\n#### Link\n\nA `<Link />` renders as an `<a>` element, the `onclick` event handler will call\n[preventDefault](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault), and push the targeted page to the\nhistory and render the desired page, which is what should be expected from a Single Page App. The default `onclick` of a\nnormal anchor element would reload the page.\n\nThe `<Link />` component also passes its children to the `<a>` element. Consider it a replacement of `<a/>` for in-app\nroutes. Except you supply a `to` attribute instead of a `href`. An example usage:\n\n```rust ,ignore\n<Link<Route> to={Route::Home}>{ \"click here to go home\" }</Link<Route>>\n```\n\nStruct variants work as expected too:\n\n```rust ,ignore\n<Link<Route> to={Route::Post { id: \"new-yew-release\".to_string() }}>{ \"Yew!\" }</Link<Route>>\n```\n\n#### Navigator API\n\nNavigator API is provided for both function components and struct components. They enable callbacks to change the\nroute. A `Navigator` instance can be obtained in either case to manipulate the route.\n\n##### Function Components\n\nFor function components, the `use_navigator` hook re-renders the component when the underlying navigator provider changes.\nHere is how to implement a button that navigates to the `Home` route when clicked.\n\n```rust ,ignore\n#[component]\npub fn MyComponent() -> Html {\n    let navigator = use_navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n\n    html! {\n        <button {onclick}>{\"Click to go home\"}</button>\n    }\n}\n```\n\nIf you want to replace the current location instead of pushing a new location onto the stack, use `navigator.replace()`\ninstead of `navigator.push()`.\n\nYou may notice `navigator` has to move into the callback, so it cannot be used again for other callbacks. Luckily `navigator`\nimplements `Clone`, here is for example how to have multiple buttons for different routes:\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew_router::prelude::*;\n\n#[component(NavItems)]\npub fn nav_items() -> Html {\n    let navigator = use_navigator().unwrap();\n\n    let go_home_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Home));\n        html! {\n            <button {onclick}>{\"click to go home\"}</button>\n        }\n    };\n\n    let go_to_first_post_button = {\n        let navigator = navigator.clone();\n        let onclick = Callback::from(move |_| navigator.push(&Route::Post { id: \"first-post\".to_string() }));\n        html! {\n            <button {onclick}>{\"click to go the first post\"}</button>\n        }\n    };\n\n    let go_to_secure_button = {\n        let onclick = Callback::from(move |_| navigator.push(&Route::Secure));\n        html! {\n            <button {onclick}>{\"click to go to secure\"}</button>\n        }\n    };\n\n    html! {\n        <>\n            {go_home_button}\n            {go_to_first_post_button}\n            {go_to_secure_button}\n        </>\n    }\n}\n```\n\n##### Struct Components\n\nFor struct components, the `Navigator` instance can be obtained through the `ctx.link().navigator()` API. The rest is\nidentical to the function component case. Here is an example of a view function that renders a single button.\n\n```rust ,ignore\nfn view(&self, ctx: &Context<Self>) -> Html {\n    let navigator = ctx.link().navigator().unwrap();\n    let onclick = Callback::from(move |_| navigator.push(&MainRoute::Home));\n    html!{\n        <button {onclick}>{\"Go Home\"}</button>\n    }\n}\n```\n\n#### Redirect\n\n`yew-router` also provides a `<Redirect />` component in the prelude. It can be used to achieve similar effects as the\nnavigator API. The component accepts a\n`to` attribute as the target route. When a `<Redirect/>` is rendered users will be redirected to the route specified in props.\nHere is an example:\n\n```rust ,ignore\n#[component(SomePage)]\nfn some_page() -> Html {\n    // made-up hook `use_user`\n    let user = match use_user() {\n        Some(user) => user,\n        // Redirects to the login page when user is `None`.\n        None => return html! {\n            <Redirect<Route> to={Route::Login}/>\n        },\n    };\n    // ... actual page content.\n}\n```\n\n:::tip `Redirect` vs `Navigator`, which to use\nThe Navigator API is the only way to manipulate route in callbacks.\nWhile `<Redirect />` can be used as return values in a component. You might also want to use `<Redirect />` in another\nnon-component context, for example in the switch function of a [Nested Router](#nested-router).\n:::\n\n### Listening to Changes\n\n#### Function Components\n\nYou can use `use_location` and `use_route` hooks. Your components will re-render when\nprovided values change.\n\n#### Struct Components\n\nIn order to react on route changes, you can pass a callback closure to the `add_location_listener()` method of `ctx.link()`.\n\n:::note\nThe location listener will get unregistered once it is dropped. Make sure to store the handle inside your\ncomponent state.\n:::\n\n```rust ,ignore\nfn create(ctx: &Context<Self>) -> Self {\n    let listener = ctx.link()\n        .add_location_listener(ctx.link().callback(\n            // handle event\n        ))\n        .unwrap();\n    MyComponent {\n        _listener: listener\n    }\n}\n```\n\n`ctx.link().location()` and `ctx.link().route::<R>()` can also be used to retrieve the location and the route once.\n\n### Query Parameters\n\n#### Specifying query parameters when navigating\n\nIn order to specify query parameters when navigating to a new route, use either `navigator.push_with_query` or\nthe `navigator.replace_with_query` functions. It uses the `ToQuery` trait to serialize the parameters into a query string for the URL. The `ToQuery` trait is automatically implemented for `serde` so any type that implements `Serialize` can be passed. In its simplest form, this is just a `HashMap` containing string pairs. In more complex scenarios the `ToQuery` trait can be implemented manually for a custom query format.\n\n#### Obtaining query parameters for the current route\n\n`location.query` is used to obtain the query parameters. It uses the `FromQuery` trait to deserialize the parameters from the query string\nin the URL. The `FromQuery` trait is automatically implemented for `serde` so any type that implements `Deserialize` can be passed. If the URL is formatted in an custom way, a manual implementation of `FromQuery` can be used.\n\n## Nested Router\n\nNested router can be useful when the app grows larger. Consider the following router structure:\n\n<!--\nThe graph is produced with the following code, with graphviz.\nTo reproduce. Save the code in a file, say `input.dot`,\nAnd run `$ dot -Tsvg input.dot  -o nested-router.svg`\n\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\"]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none]\n    SettingsNotFound -> \"Not Found\" [constraint=false]\n}\n-->\n\n<!--\nAlso the dark-themed version:\ndigraph {\n    bgcolor=transparent\n    node [shape=box style=\"filled, rounded\" fillcolor=grey color=white fontcolor=white]\n    Home; News; Contact; \"Not Found\"; Profile; Friends; Theme; SettingsNotFound [label=\"Not Found\"];\n\n    node [fillcolor=lightblue style=\"filled, rounded\" color=white fontcolor=black]\n    \"Main Router\"; \"Settings Router\";\n\n    \"Main Router\" -> {Home News Contact \"Not Found\" \"Settings Router\"} [arrowhead=none color=white]\n    \"Settings Router\" -> {SettingsNotFound Profile Friends Theme } [arrowhead=none color=white]\n    SettingsNotFound -> \"Not Found\" [constraint=false color=white]\n}\n-->\n\nimport useBaseUrl from '@docusaurus/useBaseUrl'\nimport ThemedImage from '@theme/ThemedImage'\n\n<ThemedImage\n    alt=\"nested router structure\"\n    sources={{\n        light: useBaseUrl('/img/nested-router-light.svg'),\n        dark: useBaseUrl('/img/nested-router-dark.svg'),\n    }}\n/>\n\nThe nested `SettingsRouter` handles all URLs that start with `/settings`. Additionally, it redirects URLs that are not\nmatched to the main `NotFound` route. So `/settings/gibberish` will redirect to `/404`.\n\n:::caution\n\nThough note that this is still a work in progress so the way we do this is not final\n\n:::\n\nIt can be implemented with the following code:\n\n```rust\nuse yew::prelude::*;\nuse yew_router::prelude::*;\nuse gloo::utils::window;\nuse wasm_bindgen::UnwrapThrowExt;\n\n#[derive(Clone, Routable, PartialEq)]\nenum MainRoute {\n    #[at(\"/\")]\n    Home,\n    #[at(\"/news\")]\n    News,\n    #[at(\"/contact\")]\n    Contact,\n    #[at(\"/settings\")]\n    SettingsRoot,\n    #[at(\"/settings/*\")]\n    Settings,\n    #[not_found]\n    #[at(\"/404\")]\n    NotFound,\n}\n\n#[derive(Clone, Routable, PartialEq)]\nenum SettingsRoute {\n    #[at(\"/settings\")]\n    Profile,\n    #[at(\"/settings/friends\")]\n    Friends,\n    #[at(\"/settings/theme\")]\n    Theme,\n    #[not_found]\n    #[at(\"/settings/404\")]\n    NotFound,\n}\n\nfn switch_main(route: MainRoute) -> Html {\n    match route {\n        MainRoute::Home => html! {<h1>{\"Home\"}</h1>},\n        MainRoute::News => html! {<h1>{\"News\"}</h1>},\n        MainRoute::Contact => html! {<h1>{\"Contact\"}</h1>},\n        MainRoute::SettingsRoot | MainRoute::Settings => html! { <Switch<SettingsRoute> render={switch_settings} /> },\n        MainRoute::NotFound => html! {<h1>{\"Not Found\"}</h1>},\n    }\n}\n\nfn switch_settings(route: SettingsRoute) -> Html {\n    match route {\n        SettingsRoute::Profile => html! {<h1>{\"Profile\"}</h1>},\n        SettingsRoute::Friends => html! {<h1>{\"Friends\"}</h1>},\n        SettingsRoute::Theme => html! {<h1>{\"Theme\"}</h1>},\n        SettingsRoute::NotFound => html! {<Redirect<MainRoute> to={MainRoute::NotFound}/>}\n    }\n}\n\n#[component(App)]\npub fn app() -> Html {\n    html! {\n        <BrowserRouter>\n            <Switch<MainRoute> render={switch_main} />\n        </BrowserRouter>\n    }\n}\n```\n\n### Basename\n\nIt's possible to define a basename with `yew-router`.\nA basename is a common prefix of all routes. Both the Navigator API and\n`<Switch />` component respect basename setting. All pushed routes will be\nprefixed with the basename and all switches will strip the basename before\ntrying to parse the path into a `Routable`.\n\nIf a basename prop is not supplied to the Router component, it will use\nthe href attribute of the `<base />` element in your HTML file and\nfallback to `/` if no `<base />` is present in the HTML file.\n\n## Relevant examples\n\n- [Router](https://github.com/yewstack/yew/tree/master/examples/router)\n\n## API Reference\n\n- [yew-router](https://docs.rs/yew-router/)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/concepts/suspense.mdx",
    "content": "---\ntitle: 'Suspense'\ndescription: 'Suspense for data fetching'\n---\n\nSuspense is a way to suspend component rendering whilst waiting a task\nto complete and a fallback (placeholder) UI is shown in the meanwhile.\n\nIt can be used to fetch data from server, wait for tasks to be completed\nby an agent, or perform other background asynchronous task.\n\nBefore suspense, data fetching usually happens after (Fetch-on-render) or before\ncomponent rendering (Fetch-then-render).\n\n### Render-as-You-Fetch\n\nSuspense enables a new approach that allows components to initiate data request\nduring the rendering process. When a component initiates a data request,\nthe rendering process will become suspended and a fallback UI will be\nshown until the request is completed.\n\nThe recommended way to use suspense is with hooks.\n\n```rust ,ignore\nuse yew::prelude::*;\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\nIn the above example, the `use_user` hook will suspend the component\nrendering while user information is loading and a `Loading...` placeholder will\nbe shown until `user` is loaded.\n\nTo define a hook that suspends a component rendering, it needs to return\na `SuspensionResult<T>`. When the component needs to be suspended, the\nhook should return a `Err(Suspension)` and users should unwrap it with\n`?` in which it will be converted into `Html`.\n\n```rust ,ignore\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\nstruct User {\n    name: String,\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n```\n\n#### Note on implementing suspending hooks\n\n[`Suspension::new`](https://docs.rs/yew/latest/yew/suspense/struct.Suspension.html#method.new) returns 2 values: the suspension context itself, and a suspension handle.\nThe latter is the one responsible for signaling when to re-render the suspended components, it provides 2 interchangeable ways to do so:\n\n1. Calling its [`resume`](https://docs.rs/yew/latest/yew/suspense/struct.SuspensionHandle.html#method.resume) method.\n2. Dropping the handle.\n\n:::danger\n\nThe suspension handle must be stored until it's time to update components, i.e. with newly received data;\notherwise, the suspended components will enter an infinite re-render loop, thus hampering performance.\nIn the example above, the suspension handle is preserved by being moved into a closure and passed into `on_load_user_complete`.\nWhen the hypothetical user will be loaded, the closure will be called, thus calling `handle.resume()` and re-rendering the components associated with the suspension context.\n\n:::\n\n# Complete Example\n\n```rust\nuse yew::prelude::*;\nuse yew::suspense::{Suspension, SuspensionResult};\n\n#[derive(Debug)]\nstruct User {\n    name: String,\n}\n\nfn load_user() -> Option<User> {\n    todo!()  // implementation omitted.\n}\n\nfn on_load_user_complete<F: FnOnce()>(_fn: F) {\n    todo!()  // implementation omitted.\n}\n\n#[hook]\nfn use_user() -> SuspensionResult<User> {\n    match load_user() {\n        // If a user is loaded, then we return it as Ok(user).\n        Some(m) => Ok(m),\n        None => {\n            // When user is still loading, then we create a `Suspension`\n            // and call `SuspensionHandle::resume` when data loading\n            // completes, the component will be re-rendered\n            // automatically.\n            let (s, handle) = Suspension::new();\n            on_load_user_complete(move || {handle.resume();});\n            Err(s)\n        },\n    }\n}\n\n#[component(Content)]\nfn content() -> HtmlResult {\n    let user = use_user()?;\n\n    Ok(html! {<div>{\"Hello, \"}{&user.name}</div>})\n}\n\n#[component(App)]\nfn app() -> Html {\n    let fallback = html! {<div>{\"Loading...\"}</div>};\n\n    html! {\n        <Suspense {fallback}>\n            <Content />\n        </Suspense>\n    }\n}\n```\n\n### Use Suspense in Struct Components\n\nIt's not possible to suspend a struct component directly. However, you\ncan use a function component as a [Higher Order Component](../advanced-topics/struct-components/hoc)\nto achieve suspense-based data fetching.\n\nThe [suspense example in the Yew repository](https://github.com/yewstack/yew/tree/master/examples/suspense/src/struct_consumer.rs)\ndemonstrates how to use.\n\n## Relevant examples\n\n- [Suspense](https://github.com/yewstack/yew/tree/master/examples/suspense)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/getting-started/build-a-sample-app.mdx",
    "content": "---\ntitle: 'Build a sample app'\n---\n\nOnce you have the environment ready, you can either choose to use a starter template that contains\nthe boilerplate needed for a basic Yew app or manually set up a small project.\n\n## Using a starter template\n\nInstall [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) by following their installation instructions\nthen take the following steps:\n\n### Checkout and customize project\n\n```shell\ncargo generate yewstack/yew-trunk-minimal-template\n```\n\n### Run project\n\n```shell\ntrunk serve\n```\n\n:::note\n\nTrunk [has a bug](https://github.com/trunk-rs/trunk/issues/852) on windows when `trunk serve` command fails. To workaround the issue you can run `trunk build` before running `trunk serve`.\n\n:::\n\n## Setting up the application manually\n\n### Create Project\n\nTo get started, create a new cargo project.\n\n```bash\ncargo new yew-app\n```\n\nOpen the newly created directory.\n\n```bash\ncd yew-app\n```\n\n### Run a hello world example\n\nTo verify the Rust environment is set up, run the initial project using `cargo run`. You should see\na \"Hello World!\" message.\n\n```bash\ncargo run\n# output: Hello World!\n```\n\n### Setting up the project as a Yew web application\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\n\n#### Update Cargo.toml\n\nAdd `yew` to the list of dependencies.\n\n```toml title=Cargo.toml\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n#### Update main.rs\n\nWe need to generate a template that sets up a root Component called `App` which renders a button\nthat updates its value when clicked. Replace the contents of `src/main.rs` with the following code.\n\n:::note\nThe call to `yew::Renderer::<App>::new().render()` inside the `main` function starts your application and mounts\nit to the page's `<body>` tag.\nIf you would like to start your application with any dynamic properties, you can instead use `yew::Renderer::<App>::with_props(..).render()`.\nIf you would like to mount your application to a specific element rather than the `<body>` tag, use `yew::Renderer::<App>::with_root(element).render()` where `element` is a `web_sys::Element`.\n:::\n\n```rust ,no_run, title=main.rs\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    let counter = use_state(|| 0);\n    let onclick = {\n        let counter = counter.clone();\n        move |_| {\n            let value = *counter + 1;\n            counter.set(value);\n        }\n    };\n\n    html! {\n        <div>\n            <button {onclick}>{ \"+1\" }</button>\n            <p>{ *counter }</p>\n        </div>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\n#### Create index.html\n\nFinally, add an `index.html` file in the root directory of your app.\n\n```html , title=index.html\n<!doctype html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>Yew App</title>\n    </head>\n    <body></body>\n</html>\n```\n\n## View your web application\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve\n```\n\n:::info\nAdd option '--open' to open your default browser `trunk serve --open`.\n:::\n\nTrunk will rebuild your application if you modify any of its source code files.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\n## Congratulations\n\nYou have now successfully set up your Yew development environment, and built your first web application.\n\nExperiment with this application and review the [examples](./examples.mdx) to further your learning.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/getting-started/editor-setup.mdx",
    "content": "---\ntitle: 'Editor setup'\ndescription: 'Setting your code editor'\n---\n\n:::important contribute\nUsing a different editor? Feel free to add instructions for your editor of choice.\n:::\n\n## Add a template for creating components\n\n### JetBrains IDEs\n\n1. Navigate to File | Settings | Editor | Live Templates.\n2. Select Rust and click on the + icon to add a new Live Template.\n3. Give it a name and description of your preference.\n4. Paste the following snippet(s) into the Template Text section.\n5. Change the applicability on the lower right, select Rust > Item > Module\n\nFor function components, use the following template.\n\n- (Optional) Click on Edit Variable and give `tag` a reasonable default value like \"div\", with double quotes.\n\n```rust ,ignore\n#[derive(PartialEq, Properties)]\npub struct $Name$Props {\n}\n\n#[component]\npub fn $Name$(props: &$Name$Props) -> Html {\n    html! {\n        <$tag$>$END$</$tag$>\n    }\n}\n```\n\nFor struct components, you can use the following more complicated template.\n\n```rust ,ignore\nstruct $NAME$;\n\nenum $NAME$Msg {\n}\n\nimpl Component for $NAME$ {\n    type Message = $NAME$Msg;\n    type Properties = ();\n\n    fn create(ctx: &Context<Self>) -> Self {\n        Self\n    }\n\n    fn view(&self, ctx: &Context<Self>) -> Html {\n        html! {\n            $HTML$\n        }\n    }\n}\n```\n\n### VS Code\n\n1. Navigate to File > Preferences > User Snippets.\n2. Select Rust as the language.\n3. Add the following snippet in the snippet JSON file:\n\n```json\n{\n    \"New Yew function component\": {\n        \"prefix\": \"yewfc\",\n        \"body\": [\n            \"#[derive(PartialEq, Properties)]\",\n            \"pub struct ${1:ComponentName}Props {}\",\n            \"\",\n            \"#[component]\",\n            \"pub fn $1(props: &${1}Props) -> Html {\",\n            \"    let ${1}Props {} = props;\",\n            \"    html! {\",\n            \"        <${2:div}>$0</${2}>\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a minimal Yew function component\"\n    },\n    \"New Yew struct component\": {\n        \"prefix\": \"yewsc\",\n        \"body\": [\n            \"pub struct ${1:ComponentName};\",\n            \"\",\n            \"pub enum ${1}Msg {\",\n            \"}\",\n            \"\",\n            \"impl Component for ${1} {\",\n            \"    type Message = ${1}Msg;\",\n            \"    type Properties = ();\",\n            \"\",\n            \"    fn create(ctx: &Context<Self>) -> Self {\",\n            \"        Self\",\n            \"    }\",\n            \"\",\n            \"    fn view(&self, ctx: &Context<Self>) -> Html {\",\n            \"        html! {\",\n            \"            $0\",\n            \"        }\",\n            \"    }\",\n            \"}\"\n        ],\n        \"description\": \"Create a new Yew component with a message enum\"\n    }\n}\n```\n\n## Support for the `html!` macro\n\n### JetBrains IDEs\n\nContribution Welcome!\n\n### VS Code\n\n#### The Rust-Yew extension\n\n> 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)\n\nThe Rust-Yew extension is [available on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlighting, renames, hover, and more.\n\nEmmet support should work out of the box; if not, please fall back to editing the `settings.json` file:\n\n```json\n\"emmet.includeLanguages\": {\n    \"rust\": \"html\",\n}\n```\n\n### Neovim\n\n#### Lazyvim\n\n> The below configuration works with [LazyVim](https://www.lazyvim.org) and the lazy.vim plugin. Create a file in `lua/plugins/nvim-lspconfig.lua` (or update your `lspconfig`) with:\n\n```json\nreturn {\n  {\n    \"neovim/nvim-lspconfig\",\n    init_options = {\n      userLanguages = {\n        eelixir = \"html-eex\",\n        eruby = \"erb\",\n        rust = \"html\",\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/getting-started/examples.mdx",
    "content": "---\ntitle: 'Examples'\n---\n\nThe Yew repository contains many [examples] (in various states of maintenance).\nWe recommend perusing them to get a feel for how to use different features of the framework.\nWe also welcome Pull Requests and issues for when they inevitably get neglected and need some ♥️\n\nFor more details including a list of examples, refer to the [README].\n\n:::tip\nMost of the examples have a live deployment that can be found at `https://examples.yew.rs/< example_name >`.\nClick the shield on their README page in their respective sub-folder to navigate to the live demo.\n:::\n\n[examples]: https://github.com/yewstack/yew/tree/master/examples\n[readme]: https://github.com/yewstack/yew/tree/master/examples#yew-examples\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/getting-started/introduction.mdx",
    "content": "---\ntitle: 'Getting Started'\n---\n\nYou will need a couple of tools to compile, build, package, and debug your Yew application.\nWhen getting started, we recommend using [Trunk](https://trunkrs.dev/). Trunk is a Wasm web application\nbundler for Rust.\n\n## Install Rust\n\nTo install Rust, follow the [official instructions](https://www.rust-lang.org/tools/install).\n\n:::important\nThe minimum supported Rust version (MSRV) for Yew is `1.84.0`. Older versions will not compile.\nYou can check your toolchain version using\n`rustup show` (under \"active toolchain\") or `rustc --version`. To update your\ntoolchain, run `rustup update`.\n:::\n\n## Install WebAssembly target\n\nRust can compile source codes for different \"targets\" (e.g. different processors). The compilation\ntarget for browser-based WebAssembly is called `wasm32-unknown-unknown`. The following command will\nadd the WebAssembly target to your development environment.\n\n```shell\nrustup target add wasm32-unknown-unknown\n```\n\n## Install Trunk\n\nTrunk is the recommended tool for managing deployment and packaging and is used throughout the\ndocumentation and examples.\n\n```shell\n# note that this might take a while to install because it compiles everything from scratch\n# Trunk also provides prebuilt binaries for a number of major package managers\n# See https://trunkrs.dev/#install for further details\ncargo install --locked trunk\n```\n\n### Other options\n\nThere are options other than Trunk that may be used for bundling Yew applications. You might want to try one of these options:\n\n- [`wasm-pack`](https://github.com/drager/wasm-pack/)\n- [`wasm-run`](https://github.com/IMI-eRnD-Be/wasm-run)\n- [`xtask-wasm`](https://github.com/rustminded/xtask-wasm/) (still in early development)\n\n## Next steps\n\nWith your development environment set up, you can now either proceed with reading the documentation, or\nif you like to learn by getting your hands dirty, we recommend you check out our [tutorial](../tutorial).\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\n## `_as_body` variant of `start_app` is removed\n\nThis method of controlling body has caused issues in event registration and\nSSR hydration. They have been removed. Read more in the [github issue](https://github.com/yewstack/yew/pull/2346).\n\n## New Hooks and Function Components API\n\nThe Function Components and Hooks API are re-implemented with a different mechanism:\n\n- User-defined hooks are now required to have a prefix `use_` and must be marked with the `#[hook]` attribute.\n- Hooks will now report compile errors if they are not called from the top level of a function component\n  or a user defined hook. The limitation existed in the previous version of Yew as well. In this version,\n  It is reported as a compile time error.\n\n## Automatic Message Batching\n\nThe scheduler now schedules its start to the end of the browser event loop.\nAll messages queued during in the meantime will be run in batch.\nThe running order of messages between components are no longer guaranteed, but\nmessages sent to the same component is still acknowledged in an FIFO order.\nIf multiple updates will result in a render, the component will be rendered\nonce.\n\n:::info What this means to developers?\n\nFor struct components, this means that if you send 2 messages to 2 different\ncomponents, they will not be guaranteed to be seen in the same order they are\nsent. If you send 2 messages to the same component, they will still be passed\nto the component in the order they are sent. The messages are not sent to the\ncomponent immediately so you should not assume that when the component receives\na message it still has the same state at the time the message is created.\n\nFor function components, if you store states with `use_state(_eq)`\nand the new value of that state depends on the previous value,\nyou may want to switch to `use_reducer(_eq)`. The new value of the state will\nnot be visible / acknowledged until the next time the component is rendered.\nThe reducer action works similar to messages for struct components and\nwill be sent to the reducer function in the same order as they are dispatched.\nThe reducer function can see all previous changes at the time they are run.\n\n:::\n\n## Yew Renderer\n\n`start_app*` has been replaced by `yew::Renderer`.\n\nYou need to enable feature `csr` to use `yew::Renderer`.\n\n## `ref` prop for Components\n\nComponents no longer have a `ref` prop. Trying to add a node ref to a component\nwill result in a compile error\n\nPreviously node ref passed to a component was bound to the first element rendered by it.\nIf this behavior is still desired, it is recommended to use add a `r#ref` field to the\ncomponent's properties and bind it manually\n\n## `changed` Method on Components\n\nThe method `fn changed()` has now a new argument to provide the old properties\nto the function.\n\nThe old method's signature was:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>) -> bool\n```\n\nThe new method's signature is now:\n\n```rust ,ignore\nfn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool\n```\n\nThis can be adjusted automatically in your code using this bash script (save\nyour code before running this!):\n\n```bash\nperl -p -i -e  's/fn changed\\(&mut self, (\\w+): &Context<Self>\\)/fn changed(&mut self, $1: &Context<Self>, _old_props: &Self::Properties)/g' $(find . -name \\*.rs)\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew/from-0_20_0-to-0_21_0.mdx",
    "content": "---\ntitle: 'From 0.20.0 to 0.21.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## Dependencies as first hook argument and `use_effect_with`\n\n- Replace `use_effect_with_deps` with new `use_effect_with`\n- `use_effect_with`, `use_callback`, `use_memo` now take dependencies as their first argument\n\n### Automated refactor\n\nWith the help of [https://ast-grep.github.io](https://ast-grep.github.io/guide/quick-start.html)\nHere are commands that can do the refactoring for you.\n\n```bash\nsg --pattern 'use_effect_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_effect_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_callback($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_callback($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_callback($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_callback($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_memo($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_memo($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_future_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i\nsg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_future_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\nsg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i\n```\n\n### Reasoning\n\nThis will enable more ergonomic use of hooks, consider:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\n{\n    let id = some_dep.id(); // Have to extract it in advance, some_dep is moved already in the second argument\n    use_effect_with_dep(move |_| { todo!(); drop(some_dep); }, id);\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nimpl SomeLargeStruct {\n    fn id(&self) -> u32; // Only need to use the id as cache key\n}\nlet some_dep: SomeLargeStruct = todo!();\n\nuse_effect_with(some_dep.id(), move |_| { todo!(); drop(some_dep); });\n\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew/from-0_21_0-to-0_22_0.mdx",
    "content": "---\ntitle: 'From 0.21.0 to 0.22.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## MSRV raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. Update your toolchain:\n\n```bash\nrustup update stable\n```\n\n## `#[function_component]` renamed to `#[component]`\n\nThe `#[function_component]` attribute has been renamed to `#[component]` for brevity. The old name is deprecated but still works.\n\n### Automated refactor\n\n```bash\n# Using sed (simple but also replaces in comments/strings)\nfind . -name \"*.rs\" -exec sed -i 's/#\\[function_component\\]/#[component]/g' {} +\nfind . -name \"*.rs\" -exec sed -i 's/#\\[function_component(/#[component(/g' {} +\n\n# Or using ast-grep (recommended - AST-aware, preserves comments/strings)\n# Important: Run the named pattern FIRST to preserve component names\nast-grep run -p '#[function_component($$$ARGS)]' -r '#[component($$$ARGS)]' -l rust --update-all .\nast-grep run -p '#[function_component]' -r '#[component]' -l rust --update-all .\n```\n\n:::note\nThe sed commands will also replace occurrences in comments and strings. Use ast-grep for more precise refactoring.\n:::\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\n#[function_component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello\"}</div> }\n}\n\n#[function_component(Named)]\nfn AnotherComponent() -> Html {\n    html! { <div>{\"World\"}</div> }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\n#[component]\nfn MyComponent() -> Html {\n    html! { <div>{\"Hello\"}</div> }\n}\n\n#[component(Named)]\nfn AnotherComponent() -> Html {\n    html! { <div>{\"World\"}</div> }\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `class=(...)` syntax removed\n\nThe deprecated `class=(expr)` syntax has been removed. Use `class={classes!(...)}` instead.\n\n### Finding occurrences\n\n```bash\n# Find all files using the old class=(...) syntax\ngrep -rn \"class=(\" --include=\"*.rs\" .\n```\n\n### Manual refactor\n\nThe transformation is straightforward: wrap the tuple contents with `classes!()` and change parentheses to braces:\n\n- `class=(a, b)` → `class={classes!(a, b)}`\n- `class=(expr)` → `class={classes!(expr)}`\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nhtml! {\n    <div class=(some_class, other_class)>{\"Content\"}</div>\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nhtml! {\n    <div class={classes!(some_class, other_class)}>{\"Content\"}</div>\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `ToHtml` trait removed\n\nThe `ToHtml` trait has been removed. Use `IntoPropValue` for custom type conversions.\n\n## For-loops in `html!` macro\n\nYou can now use for-loops directly in the `html!` macro. This is optional but provides cleaner syntax:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before (still works)\" default>\n\n```rust ,ignore\nhtml! {\n    <ul>\n        { for items.iter().map(|item| html! { <li key={item.id}>{ &item.name }</li> }) }\n    </ul>\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After (new syntax)\">\n\n```rust ,ignore\nhtml! {\n    <ul>\n        for item in items {\n            <li key={item.id}>{ &item.name }</li>\n        }\n    </ul>\n}\n```\n\n  </TabItem>\n</Tabs>\n\n## `use_effect_with` no longer requires `|| ()` return\n\nEffect hooks no longer require returning `|| ()` when there's no cleanup:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\nuse_effect_with(deps, |deps| {\n    // do something\n    || ()  // had to return this\n});\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\nuse_effect_with(deps, |deps| {\n    // do something\n    // no return needed!\n});\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew/from-0_22_0-to-0_23_0.mdx",
    "content": "---\ntitle: 'From 0.22.0 to 0.23.0'\n---\n\nimport Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'\n\n## `use_reducer` no longer re-renders on identity dispatches\n\n`use_reducer` now skips re-rendering when the reducer returns the same `Rc` (checked by pointer equality). Previously, every dispatch triggered a re-render regardless.\n\nIf your reducer has a code path that returns `self` unchanged and you relied on that causing a re-render, replace it with `use_force_update`:\n\n<Tabs>\n  <TabItem value=\"before\" label=\"Before\" default>\n\n```rust ,ignore\npub enum Action {\n    Increment,\n    ForceRefresh,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n            // This no longer triggers a re-render in 0.23!\n            Action::ForceRefresh => self,\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={\n                let state = state.clone();\n                move |_| state.dispatch(Action::Increment)\n            }>\n                { \"+1\" }\n            </button>\n            <button onclick={move |_| state.dispatch(Action::ForceRefresh)}>\n                { \"Refresh\" }\n            </button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n  <TabItem value=\"after\" label=\"After\">\n\n```rust ,ignore\npub enum Action {\n    Increment,\n}\n\nstruct State {\n    count: u32,\n}\n\nimpl Reducible for State {\n    type Action = Action;\n\n    fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {\n        match action {\n            Action::Increment => Rc::new(Self {\n                count: self.count + 1,\n            }),\n        }\n    }\n}\n\n#[component]\npub fn App() -> Html {\n    use_effect(|| {\n        tracing::info!(\"This cursed component does some effects on render\");\n    });\n    let state = use_reducer(|| State { count: 0 });\n    let trigger = use_force_update();\n    html! {\n        <div>\n            <p>{ state.count }</p>\n            <button onclick={move |_| state.dispatch(Action::Increment)}>{ \"+1\" }</button>\n            <button onclick={move |_| trigger.force_update()}>{ \"Refresh\" }</button>\n        </div>\n    }\n}\n```\n\n  </TabItem>\n</Tabs>\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-agent/from-0_0_0-to-0_1_0.mdx",
    "content": "---\ntitle: 'From 0.0.0 to 0.1.0'\n---\n\nThis is the first release of `yew-agents` being separated from `yew`\n\nThe only thing you will need to do is change the import paths from `yew::*` to `yew_agents::*`\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-agent/from-0_1_0-to-0_2_0.mdx",
    "content": "---\ntitle: 'From 0.1.0 to 0.2.0'\n---\n\n## Removal of `Context` and `Job` Agents\n\nThe `Context` and `Job` Agents have been removed in favour of Yew's Context API.\n\nYou can see the updated [`pub_sub`](https://github.com/yewstack/yew/tree/master/examples/pub_sub)\nwhich demonstrate how to use the context API.\n\nFor users of `yew_agent::utils::store`, you may switch to third party solutions like: [Yewdux](https://github.com/intendednull/yewdux) or [Bounce](https://github.com/futursolo/bounce).\n\n## `Threaded` has been separated into `PublicAgent` and `PrivateAgent`\n\nReplace `use yew_agent::Threaded;` with `use yew_agent::PublicAgent;`.\n\n:::note\n\n`Threaded` was never implemented for Private Agents.\nAll existing web worker-based agents are Public Agents.\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-agent/from-0_3_0-to-0_4_0.mdx",
    "content": "---\ntitle: 'From 0.3.0 to 0.4.0'\n---\n\n## MSRV raised to 1.84.0\n\nThe minimum supported Rust version is now **1.84.0**. Update your toolchain:\n\n```bash\nrustup update stable\n```\n\n## gloo-worker vendored\n\nThe external dependency on `gloo-worker` has been removed. All worker functionality is now built into `yew-agent`.\n\n### Update imports\n\nIf you were importing types from `gloo-worker`, update to import from `yew_agent`:\n\n```rust ,ignore\n// Before\nuse gloo_worker::{Spawnable, Worker, WorkerScope};\n\n// After\nuse yew_agent::prelude::*;\n// or\nuse yew_agent::{Spawnable, Worker, WorkerScope};\n```\n\n### Codec trait\n\nThe `Codec` trait is now defined in `yew-agent`:\n\n```rust ,ignore\n// Before\nuse gloo_worker::Codec;\n\n// After\nuse yew_agent::Codec;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-agent/from-0_4_0-to-0_5_0.mdx",
    "content": "---\ntitle: 'From 0.4.0 to 0.5.0'\n---\n\nNo breaking changes. Update yew-agent to 0.5.0 in your `Cargo.toml`.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-router/from-0_15_0-to-0_16_0.mdx",
    "content": "---\ntitle: 'From 0.15.0 to 0.16.0'\n---\n\nThe router API has been completely rewritten in `0.16.0`.\n\nBecause it is such a radical change, there are too many things to list out here, so we highly\nrecommend to read the updated [router documentation](./../../concepts/router) and adapt your app\naccordingly.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-router/from-0_16_0-to-0_17_0.mdx",
    "content": "---\ntitle: 'From 0.16.0 to 0.17.0'\n---\n\n## `Switch::render` is no longer needed\n\nThe `<Switch />` component now accepts a closure of `Fn(Routable) -> Html` as\nthe render function directly.\n\n## `navigator` API\n\nThe History API has been replaced with the Navigator API.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/migration-guides/yew-router/from-0_19_0-to-0_20_0.mdx",
    "content": "---\ntitle: 'From 0.19.0 to 0.20.0'\n---\n\nNo breaking changes. Update yew-router to 0.20.0 in your `Cargo.toml`.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/more/css.mdx",
    "content": "---\ntitle: 'CSS'\n---\n\nYew does not ship built-in CSS support, but the community maintains several styling\nsolutions. Below are actively maintained projects you can use today.\n\n#### Styling Solutions\n\n- [stylist](https://github.com/futursolo/stylist-rs) - A CSS-in-Rust styling solution.\n- [tailwind-css](https://github.com/thedodd/trunk/tree/master/examples/yew-tailwindcss) - Tailwind Utility Classes.\n\n:::important contribute\nIf you're developing a project adding styles to Yew please submit a PR adding yourself to this list!\n:::\n\n---\n\n#### Inactive Projects\n\nThe projects below are no longer actively maintained but may still serve as useful\nreferences for learning or as starting points for new efforts. If you're interested\nin reviving or continuing any of them, contributions are welcome!\n\n- [yew_styles](https://github.com/spielrs/yew_styles) - A styling framework for Yew without any JavaScript dependencies.\n- [yew-mdc](https://github.com/Follpvosten/yew-mdc) - Material Design Components.\n- [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUI CSS Components.\n- [Yewtify](https://github.com/yewstack/yewtify) – Implements the features provided by the Vuetify framework in Yew.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/more/debugging.mdx",
    "content": "---\ntitle: 'Debugging'\n---\n\n## Panics\n\nYew automatically logs panics in the browser console.\n\n## Console Logging\n\nIn JavaScript, `console.log()` is used to log to the browser console. Some options for Yew are listed below.\n\n### [`wasm-logger`](https://crates.io/crates/wasm-logger)\n\n`wasm-logger` crate integrates with [`log`](https://crates.io/crates/log) crate to send the log level, source line, and filename to the browser console.\n\n```rust ,ignore\nuse log::info;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    wasm_logger::init(wasm_logger::Config::default());\n\n    let object = JsValue::from(\"world\");\n    info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n### [`gloo-console`](https://crates.io/crates/gloo-console)\n\nThis crate is part of Gloo, a collection of libraries providing ergonomic Rust wrappers for browser APIs.\nThe `log!` macro can take a `JsValue` directly which is slightly easier to use than `wasm_logger`.\n\n```rust ,ignore\nuse gloo_console::log;\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let object = JsValue::from(\"world\");\n    log!(\"Hello\", object)\n}\n```\n\n### [`tracing-web`](https://crates.io/crates/tracing-web)\n\n`tracing-web` can be used with [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) to output messages to the browser console.\n\n```rust ,ignore\nuse tracing_subscriber::{\n    fmt::{\n        format::{FmtSpan, Pretty},\n        time::UtcTime,\n    },\n    prelude::*,\n};\nuse wasm_bindgen::JsValue;\n\nfn main() {\n    let fmt_layer = tracing_subscriber::fmt::layer()\n        .with_ansi(false)\n        .with_timer(UtcTime::rfc_3339())\n        .with_writer(tracing_web::MakeConsoleWriter)\n        .with_span_events(FmtSpan::ACTIVE);\n    let perf_layer = tracing_web::performance_layer().with_details_from_fields(Pretty::default());\n\n    tracing_subscriber::registry()\n        .with(fmt_layer)\n        .with(perf_layer)\n        .init();\n    let object = JsValue::from(\"world\");\n    tracing::info!(\"Hello {}\", object.as_string().unwrap());\n}\n```\n\n## Debugging component lifecycles\n\n[`tracing`](https://crates.io/crates/tracing) can be used to collect event information related to a component's lifecycle. `tracing` also comes with a feature flag for `log` support, which integrates nicely with `wasm-logger`.\n\n[Compile time filters](https://docs.rs/tracing/latest/tracing/level_filters/index.html#compile-time-filters) can be used to adjust verbosity or disable logging, which should result in a smaller Wasm file.\n\n## Source Maps\n\nThere is [some support](https://developer.chrome.com/blog/wasm-debugging-2019/#enter-dwarf) for source maps.\nHowever, some configuration is required.\n\n## Past Articles\n\nSome past articles on the state of debugging in WebAssembly in Rust can be found below. They may serve as interesting reads.\n\n\\[Dec 2019\\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)\n\n> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \\(Binaryen\\) and wasm-pack \\(wasm-bindgen\\) does not support updating DWARF information on transformations they perform yet.\n\n\\[2020\\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)\n\n> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.\n\n\\[2019\\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)\n\n> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/more/deployment.mdx",
    "content": "---\ntitle: 'Deployment'\ndescription: 'Deploying Yew applications'\n---\n\nWhen you are ready to deploy your Yew application to a server, you have various options for deployment.\n\n`trunk build --release` builds your app in release mode. Set up your HTTP server so that it serves `index.html` whenever your site is visited, and requests to static paths like `index_<hash>.js` and `index_bg_<hash>.wasm` are served with the contents of their respective contents from the dist directory generated by trunk.\n\n:::important A note about `trunk serve --release`\nDo **not** use `trunk serve --release` to serve your application in production.\nIt should only be used for testing the release build during development\n:::\n\n## Server configuration\n\n### Serving `index.html` as a fallback\n\nIf the application uses the [Yew router](concepts/router.mdx), you must configure the server to return the `index.html` when asked for a file that it does not have.\n\nAn application with Yew router is built as a [Single Page Application (SPA)](https://developer.mozilla.org/en-US/docs/Glossary/SPA). When the user navigates to a URL from within a running client, the router interprets the URL and routes to that page.\n\nBut on a fresh load, such as when navigating to the page by entering it in the address bar or refreshing the page, all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router. A wrongly configured server would return with the status 404 - Not Found.\n\nBy returning `index.html` instead, the app loads as it normally would, as if the request was for `/` until the router notices that the route is `/show/42` and displays the appropriate contents.\n\n### Configuring correct MIME-type for Web Assembly asset.\n\nThe WASM files must be served with the [Content-Type header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) set to `application/wasm` MIME-type.\n\nMost servers and hosting services already do this by default. If yours does not, consult its documentation. An incorrect MIME type will, in most web browsers, result in an error similar to the following:\n\n```ignore\n`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n TypeError: WebAssembly: Response has unsupported MIME type 'text/plain' expected 'application/wasm'\n```\n\n## Building for Relative Paths\n\nBy default, trunk will assume that your site is being served at `/` and build the site accordingly. This behavior can be overridden by adding `<base data-trunk-public-url />` to the `index.html` file. Trunk rewrites this tag to contain the value passed to `--public-url`. Yew router automatically detects the presence of `<base />` and handles it appropriately.\n\n## Customizing behavior using environment variables\n\nIt is common to customize the build environment by using environment variables. Since the app is run in a browser, we cannot read the environment variables at runtime.\nThe [`std::env!`](https://doc.rust-lang.org/std/macro.env.html) macro can be used to obtain a value of an environment variable at compile time.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/more/roadmap.mdx",
    "content": "---\ntitle: 'Roadmap'\ndescription: 'The planned feature roadmap for the Yew framework'\n---\n\n## Prioritization\n\nThe prioritization of upcoming features and focuses of the framework is determined by the community.\nIn Spring 2020, a developer survey was sent out to collect feedback on the direction of the project.\nYou can find the summary in the [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D).\n\n:::note\nStatus of all major initiatives can be tracked on the Yew Github [project board](https://github.com/yewstack/yew/projects)\n:::\n\n## Focuses\n\n1. Top Requested Features\n2. Production Readiness\n3. Documentation\n4. Pain Points\n\n### Most requested features\n\n1. [Functional Components](https://github.com/yewstack/yew/projects/3)\n2. [Component Library](https://github.com/yewstack/yew/projects/4)\n3. Better state management\n4. [Server side rendering](https://github.com/yewstack/yew/projects/5)\n\n### Issues needed for production readiness\n\n- Improve Yew test coverage\n- Reduce binary size\n- [Benchmark performance](https://github.com/yewstack/yew/issues/5)\n\n### Documentation\n\n- Create tutorial\n- Simplify project setup\n\n### Pain points\n\n- [Component boilerplate](https://github.com/yewstack/yew/issues/830)\n- [Agents](https://github.com/yewstack/yew/projects/6)\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/more/testing.mdx",
    "content": "---\ntitle: 'Testing apps'\ndescription: 'Testing your app'\n---\n\n:::info\nWe are working on making it easy to test components, but this is currently a work in progress.\n\nSupport for [shallow rendering](https://github.com/yewstack/yew/issues/1413) can be found in the GitHub repository.\n:::\n\n## Snapshot testing\n\nYew exposes the `yew::tests::layout_tests` module to facilitate snapshot testing of components.\n\n:::important contribute\nHelp improve the documentation for snapshot testing.\n:::\n\n## wasm_bindgen_test\n\nThe Rust/WASM working group maintains a crate called [`wasm_bindgen_test`](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nwhich allows you to run tests in a browser in a similar fashion to how the built-in `#[test]` procedural macro works.\nMore information is given in the [Rust Wasm working group's documentation](https://wasm-bindgen.github.io/wasm-bindgen/wasm-bindgen-test/index.html)\nfor this module.\n"
  },
  {
    "path": "website/versioned_docs/version-0.23/tutorial/index.mdx",
    "content": "---\ntitle: 'Tutorial'\nslug: /tutorial\n---\n\n## Introduction\n\nIn this hands-on tutorial, we will take a look at how we can use Yew to build web applications.\n**Yew** is a modern [Rust](https://www.rust-lang.org/) framework for building front-end web apps using [WebAssembly](https://webassembly.org/).\nYew encourages a reusable, maintainable, and well-structured architecture by leveraging Rust's powerful type system.\nA large ecosystem of community-created libraries, known in Rust as [crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html),\nprovide components for commonly-used patterns such as state management.\n[Cargo](https://doc.rust-lang.org/cargo/), the package manager for Rust, allows us to take advantage of the\nnumerous crates available on [crates.io](https://crates.io), such as Yew.\n\n### What we are going to build\n\nRustconf is an intergalactic gathering of the Rust community that happens annually.\nRustconf 2020 had a plethora of talks that provided a good amount of information.\nIn this hands-on tutorial, we will be building a web application to help fellow Rustaceans\nget an overview of the talks and watch them all from one page.\n\n## Setting up\n\n### Prerequisites\n\nThis tutorial assumes you are already familiar with Rust. If you are new to Rust,\nthe free [Rust Book](https://doc.rust-lang.org/book/ch00-00-introduction.html) offers a great starting point for\nbeginners and continues to be an excellent resource even for experienced Rust developers.\n\nEnsure the latest version of Rust is installed by running `rustup update` or by\n[installing rust](https://www.rust-lang.org/tools/install) if you have not already done so.\n\nAfter installing Rust, you can use Cargo to install `trunk` by running:\n\n```bash\ncargo install trunk\n```\n\nWe will also need to add the WASM build target by running:\n\n```bash\nrustup target add wasm32-unknown-unknown\n```\n\n### Setting up the project\n\nFirst, create a new cargo project:\n\n```bash\ncargo new yew-app\ncd yew-app\n```\n\nTo verify the Rust environment is set up properly, run the initial project using the cargo build tool.\nAfter the output about the build process, you should see the expected \"Hello, world!\" message.\n\n```bash\ncargo run\n```\n\n## Our first static page\n\nTo convert this simple command line application to a basic Yew web application, a few changes are needed.\nUpdate the files as follows:\n\n```toml title=\"Cargo.toml\" {7}\n[package]\nname = \"yew-app\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nyew = { version = \"0.23\", features = [\"csr\"] }\n```\n\n:::info\n\nYou only need the feature `csr` if you are building an application.\nIt will enable the `Renderer` and all client-side rendering-related code.\n\nIf you are making a library, do not enable this feature as it will pull in\nclient-side rendering logic into the server-side rendering bundle.\n\nIf you need the Renderer for testing or examples, you should enable it\nin the `dev-dependencies` instead.\n\n:::\n\n```rust ,no_run title=\"src/main.rs\"\nuse yew::prelude::*;\n\n#[component]\nfn App() -> Html {\n    html! {\n        <h1>{ \"Hello World\" }</h1>\n    }\n}\n\nfn main() {\n    yew::Renderer::<App>::new().render();\n}\n```\n\nNow, let's create an `index.html` at the root of the project.\n\n```html title=\"index.html\"\n<!doctype html>\n<html lang=\"en\">\n    <head></head>\n    <body></body>\n</html>\n```\n\n### Start the development server\n\nRun the following command to build and serve the application locally.\n\n```bash\ntrunk serve --open\n```\n\n:::info\nRemove option '--open' to not open your default browser `trunk serve`.\n:::\n\nTrunk will open your application in your default browser, watch the project directory and helpfully rebuild your\napplication if you modify any source files.\nThis will fail if the socket is being used by another application.\nBy default server will be listening at address '127.0.0.1' and port '8080' => [http://localhost:8080](http://127.0.0.1:8080).\nTo change it, create the following file and edit as needed:\n\n```toml title=\"Trunk.toml\"\n[serve]\n# The address to serve on LAN.\naddress = \"127.0.0.1\"\n# The address to serve on WAN.\n# address = \"0.0.0.0\"\n# The port to serve on.\nport = 8000\n```\n\nIf you are curious, you can run `trunk help` and `trunk help <subcommand>` for more details on what is happening.\n\n### Congratulations\n\nYou have now successfully set up your Yew development environment and built your first Yew web application.\n\n## Building HTML\n\nYew makes use of Rust's procedural macros and provides us with a syntax similar to JSX (an extension to JavaScript\nwhich allows you to write HTML-like code inside JavaScript) to create the markup.\n\n### Converting classic HTML\n\nSince we already have a pretty good idea of what our website will look like, we can simply translate our mental draft\ninto a representation compatible with `html!`. If you are comfortable writing simple HTML, you should have no problem\nwriting marking inside `html!`. It is important to note that the macro does differ from HTML in a few ways:\n\n1. Expressions must be wrapped in curly braces (`{ }`)\n2. There must only be one root node. If you want to have multiple elements without wrapping them in a container,\n   an empty tag/fragment (`<> ... </>`) is used\n3. Elements must be closed properly.\n\nWe want to build a layout that looks something like this in raw HTML:\n\n```html\n<h1>RustConf Explorer</h1>\n<div>\n    <h3>Videos to watch</h3>\n    <p>John Doe: Building and breaking things</p>\n    <p>Jane Smith: The development process</p>\n    <p>Matt Miller: The Web 7.0</p>\n    <p>Tom Jerry: Mouseless development</p>\n</div>\n<div>\n    <h3>John Doe: Building and breaking things</h3>\n    <img\n        src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\"\n        alt=\"video thumbnail\"\n    />\n</div>\n```\n\nNow, let's convert this HTML into `html!`. Type (or copy/paste) the following snippet into the body of `app` function\nsuch that the value of `html!` is returned by the function\n\n```rust {3-21}\n#[component]\nfn App() -> Html {\n-   html! {\n-       <h1>{ \"Hello World\" }</h1>\n-   }\n+   html! {\n+       <>\n+           <h1>{ \"RustConf Explorer\" }</h1>\n+           <div>\n+               <h3>{ \"Videos to watch\" }</h3>\n+               <p>{ \"John Doe: Building and breaking things\" }</p>\n+               <p>{ \"Jane Smith: The development process\" }</p>\n+               <p>{ \"Matt Miller: The Web 7.0\" }</p>\n+               <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+           </div>\n+           <div>\n+               <h3>{ \"John Doe: Building and breaking things\" }</h3>\n+               <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n+           </div>\n+       </>\n+   }\n}\n```\n\nRefresh the browser page, and you should see the following output displayed:\n\n![Running WASM application screenshot](/img/tutorial_application_screenshot.png)\n\n### Using Rust language constructs in the markup\n\nA big advantage of writing markup in Rust is that we get all the coolness of Rust in our markup.\nNow, instead of hardcoding the list of videos in the HTML, let's define them as a `Vec` of `Video` structs.\nWe create a simple `struct` (in `main.rs` or any file of our choice) that will hold our data.\n\n```rust\n#[derive(Clone, PartialEq)]\nstruct Video {\n    id: usize,\n    title: AttrValue,\n    speaker: AttrValue,\n    url: AttrValue,\n}\n```\n\nNext, we will create instances of this struct in our `app` function and use those instead of hardcoding the data:\n\n```rust {3-29}\n#[component]\nfn App() -> Html {\n+   let videos = vec![\n+       Video {\n+           id: 1,\n+           title: \"Building and breaking things\".into(),\n+           speaker: \"John Doe\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 2,\n+           title: \"The development process\".into(),\n+           speaker: \"Jane Smith\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 3,\n+           title: \"The Web 7.0\".into(),\n+           speaker: \"Matt Miller\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+       Video {\n+           id: 4,\n+           title: \"Mouseless development\".into(),\n+           speaker: \"Tom Jerry\".into(),\n+           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n+       },\n+   ];\n+\n```\n\nTo display them, we can use a `for` loop right in the macro in place of the hardcoded HTML:\n\n```rust {6-12}\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <p>{ \"John Doe: Building and breaking things\" }</p>\n-               <p>{ \"Jane Smith: The development process\" }</p>\n-               <p>{ \"Matt Miller: The Web 7.0\" }</p>\n-               <p>{ \"Tom Jerry: Mouseless development\" }</p>\n+               for video in &videos {\n+                   <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+               }\n            </div>\n            // ...\n        </>\n    }\n```\n\n:::tip\nKeys on list items help Yew keep track of which items have changed in the list, resulting in faster re-renders.\n[It is always recommended to use keys in lists](/concepts/html/lists.mdx#keyed-lists).\n:::\n\n## Components\n\nComponents are the building blocks of Yew applications. By combining components, which can be made of other components,\nwe build our application. By structuring our components for re-usability and keeping them generic, we will be able to use\nthem in multiple parts of our application without having to duplicate code or logic.\n\nThe `app` function we have been using so far is a component, called `App`. It is a \"function component\".\nThere are two different types of components in Yew.\n\n1. Struct Components\n2. Function Components\n\nIn this tutorial, we will be using function components.\n\nNow, let's split up our `App` component into smaller components. We begin by extracting the videos list into\nits own component.\n\n```rust\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n}\n\n#[component]\nfn VideosList(VideosListProps { videos }: &VideosListProps) -> Html {\n    html! {\n        for video in videos {\n            <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }\n}\n```\n\nNotice the parameters of our `VideosList` function component. A function component takes only one argument which\ndefines its \"props\" (short for \"properties\"). Props are used to pass data down from a parent component to a child component.\nIn this case, `VideosListProps` is a struct that defines the props.\n\n:::important\nThe struct used for props must implement `Properties` by deriving it.\n:::\n\nNow, we can update our `App` component to make use of `VideosList` component.\n\n```rust {9-12}\n#[component]\nfn App() -> Html {\n    // ...\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               for video in &videos {\n-                   <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n-               }\n+               <VideosList {videos} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\nBy looking at the browser window, we can verify that the lists are rendered as they should be.\nWe have moved the rendering logic of lists to its component. This shortens the `App` component’s source code,\nmaking it easier for us to read and understand.\n\n### Making it interactive\n\nThe final goal here is to display the selected video. To do that, `VideosList` component needs to \"notify\" its\nparent when a video is selected, which is done via a `Callback`. This concept is called \"passing handlers\".\nWe modify its props to take an `on_click` callback:\n\n```rust {4}\n#[derive(Properties, PartialEq)]\nstruct VideosListProps {\n    videos: Vec<Video>,\n+   on_click: Callback<Video>,\n}\n```\n\nThen we modify the `VideosList` component to \"emit\" the selected video to the callback.\n\n```rust {2-18}\n#[component]\n-fn VideosList(VideosListProps { videos }: &VideosListProps) -> Html {\n+fn VideosList(VideosListProps { videos, on_click }: &VideosListProps) -> Html {\n+   let on_select = |video: &Video| {\n+       let on_click = on_click.clone();\n+       let video = video.clone();\n+       Callback::from(move |_| {\n+           on_click.emit(video.clone())\n+       })\n+   };\n+\n    html! {\n        for video in videos {\n-           <p key={video.id}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n+           <p key={video.id} onclick={on_select(video)}>{format!(\"{}: {}\", video.speaker, video.title)}</p>\n        }\n    }\n}\n```\n\nNext, we need to modify the usage of `VideosList` to pass that callback. But before doing that, we should create\na new component, `VideoDetails`, that is displayed when a video is clicked.\n\n```rust\n#[derive(Properties, PartialEq)]\nstruct VideosDetailsProps {\n    video: Video,\n}\n\n#[component]\nfn VideoDetails(VideosDetailsProps { video }: &VideosDetailsProps) -> Html {\n    html! {\n        <div>\n            <h3>{ &*video.title }</h3>\n            <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n        </div>\n    }\n}\n```\n\nNow, modify the `App` component to display `VideoDetails` component whenever a video is selected.\n\n```rust {3-11,18-19,21-28}\n        },\n    ];\n+\n+   let selected_video = use_state(|| None);\n+\n+   let on_video_select = {\n+       let selected_video = selected_video.clone();\n+       Callback::from(move |video: Video| {\n+           selected_video.set(Some(video))\n+       })\n+   };\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <VideosList {videos} />\n+               <VideosList {videos} on_click={on_video_select} />\n            </div>\n+           if let Some(video) = &*selected_video {\n+               <VideoDetails video={video.clone()} />\n+           }\n-           <div>\n-               <h3>{ \"John Doe: Building and breaking things\" }</h3>\n-               <img src=\"https://placehold.co/640x360.png?text=Video+Player+Placeholder\" alt=\"video thumbnail\" />\n-           </div>\n        </>\n    }\n}\n```\n\n### Handling state\n\nRemember the `use_state` used earlier? That is a special function, called a \"hook\". Hooks are used to \"hook\" into\nthe lifecycle of a function component and perform actions. You can learn more about this hook, and others\n[here](concepts/function-components/hooks/introduction.mdx#pre-defined-hooks).\n\n:::note\nStruct components act differently. See [the documentation](advanced-topics/struct-components/introduction.mdx) to learn about those.\n:::\n\n## Fetching data (using external REST API)\n\nIn a real-world application, data will usually come from an API instead of being hardcoded. Let's fetch our\nvideos list from an external source. For this we will need to add the following crates:\n\n- [`gloo-net`](https://crates.io/crates/gloo-net)\n  For making the fetch call.\n- [`serde`](https://serde.rs) with derive features\n  For de-serializing the JSON response\n- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)\n  For executing Rust Future as a Promise\n\nLet's update the dependencies in `Cargo.toml` file:\n\n```toml title=\"Cargo.toml\" {2-6}\n[dependencies]\n-yew = { version = \"0.23\", features = [\"csr\"] }\n+yew = { version = \"0.23\", features = [\"csr\", \"serde\"] }\n+gloo-net = \"0.6\"\n+serde = { version = \"1.0\", features = [\"derive\"] }\n+wasm-bindgen-futures = \"0.4\"\n```\n\nYew's `serde` feature enables integration with the `serde` crate, the important point for us is that\nit adds a `serde::Deserialize` impl to `AttrValue`.\n\n:::note\nWhen choosing dependencies make sure they are `wasm32` compatible!\nOtherwise you won't be able to run your application.\n:::\n\nUpdate the `Video` struct to derive the `Deserialize` trait:\n\n```rust {2,4-5}\nuse yew::prelude::*;\n+use serde::Deserialize;\n// ...\n-#[derive(Clone, PartialEq)]\n+#[derive(Clone, PartialEq, Deserialize)]\nstruct Video {\n    id: usize,\n    title: AttrValue,\n    speaker: AttrValue,\n    url: AttrValue,\n}\n```\n\nNow as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data\n\n```rust {2,6-50,59-60}\nuse yew::prelude::*;\n+use gloo_net::http::Request;\n\n#[component]\nfn App() -> Html {\n-   let videos = vec![\n-       Video {\n-           id: 1,\n-           title: \"Building and breaking things\".into(),\n-           speaker: \"John Doe\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 2,\n-           title: \"The development process\".into(),\n-           speaker: \"Jane Smith\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 3,\n-           title: \"The Web 7.0\".into(),\n-           speaker: \"Matt Miller\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-       Video {\n-           id: 4,\n-           title: \"Mouseless development\".into(),\n-           speaker: \"Tom Jerry\".into(),\n-           url: \"https://youtu.be/PsaFVLr8t4E\".into(),\n-       },\n-   ];\n-\n+   let videos = use_state(|| vec![]);\n+   {\n+       let videos = videos.clone();\n+       use_effect_with((), move |_| {\n+           let videos = videos.clone();\n+           wasm_bindgen_futures::spawn_local(async move {\n+               let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+                   .send()\n+                   .await\n+                   .unwrap()\n+                   .json()\n+                   .await\n+                   .unwrap();\n+               videos.set(fetched_videos);\n+           });\n+           || ()\n+       });\n+   }\n\n    // ...\n\n    html! {\n        <>\n            <h1>{ \"RustConf Explorer\" }</h1>\n            <div>\n                <h3>{ \"Videos to watch\" }</h3>\n-               <VideosList {videos} on_click={on_video_select} />\n+               <VideosList videos={(*videos).clone()} on_click={on_video_select} />\n            </div>\n            // ...\n        </>\n    }\n}\n```\n\n:::note\nWe are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have\n[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).\n:::\n\nNow, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.\nTo fix that, we need a proxy server. Luckily trunk provides that.\n\nUpdate the following line:\n\n```rust {2-3}\n-               let fetched_videos: Vec<Video> = Request::get(\"https://yew.rs/tutorial/data.json\")\n+               let fetched_videos: Vec<Video> = Request::get(\"/tutorial/data.json\")\n```\n\nNow, rerun the server with the following command:\n\n```bash\ntrunk serve --proxy-backend=https://yew.rs/tutorial\n```\n\nRefresh the tab and everything should work as expected.\n\n## Wrapping up\n\nCongratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.\n\n## What's next\n\nThis application is very far from perfect or useful. After going through this tutorial,\nyou can use it as a jumping-off point to explore more advanced topics.\n\n### Styles\n\nOur apps look very ugly. There is no CSS or any kind of style.\nUnfortunately, Yew does not offer a built-in way to style components. See [Trunk's assets](https://trunkrs.dev/assets/)\nto learn how to add style sheets.\n\n### More libraries\n\nOur app made use of only a few external dependencies. There are lots of crates out there that can be used.\nSee [external libraries](/community/external-libs) for more details.\n\n### Learning more about Yew\n\nRead our [official documentation](../getting-started/introduction.mdx). It explains a lot of concepts in much more detail.\nTo learn more about the Yew API, see our [API docs](https://docs.rs/yew).\n\n<!-- COMBINE CODE BLOCKS -->\n"
  },
  {
    "path": "website/versioned_sidebars/version-0.20-sidebars.json",
    "content": "{\n    \"docs\": [\n        {\n            \"type\": \"category\",\n            \"label\": \"Getting Started\",\n            \"link\": {\n                \"type\": \"doc\",\n                \"id\": \"getting-started/introduction\"\n            },\n            \"items\": [\n                \"getting-started/build-a-sample-app\",\n                \"getting-started/examples\",\n                \"getting-started/editor-setup\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Concepts\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Yew concepts\",\n                \"description\": \"Learn about the important Yew concepts!\"\n            },\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Using Basic Web Technologies In Yew\",\n                    \"link\": {\n                        \"type\": \"generated-index\",\n                        \"title\": \"Yew's Take on Basic Web Technologies\",\n                        \"description\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may need in one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\"\n                    },\n                    \"items\": [\n                        \"concepts/basic-web-technologies/html\",\n                        \"concepts/basic-web-technologies/css\",\n                        \"concepts/basic-web-technologies/js\",\n                        \"concepts/basic-web-technologies/wasm-bindgen\",\n                        \"concepts/basic-web-technologies/web-sys\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/function-components/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/function-components/properties\",\n                        \"concepts/function-components/callbacks\",\n                        \"concepts/function-components/children\",\n                        \"concepts/function-components/pure-components\",\n                        {\n                            \"type\": \"category\",\n                            \"label\": \"Hooks\",\n                            \"link\": {\n                                \"type\": \"doc\",\n                                \"id\": \"concepts/function-components/hooks/introduction\"\n                            },\n                            \"items\": [\n                                \"concepts/function-components/hooks/custom-hooks\"\n                            ]\n                        },\n                        \"concepts/function-components/node-refs\",\n                        \"concepts/function-components/state\",\n                        \"concepts/function-components/communication\",\n                        \"concepts/function-components/generics\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"HTML\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/html/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/html/components\",\n                        \"concepts/html/elements\",\n                        \"concepts/html/events\",\n                        \"concepts/html/classes\",\n                        \"concepts/html/fragments\",\n                        \"concepts/html/lists\",\n                        \"concepts/html/literals-and-expressions\",\n                        \"concepts/html/conditional-rendering\"\n                    ]\n                },\n                \"concepts/agents\",\n                \"concepts/contexts\",\n                \"concepts/router\",\n                \"concepts/suspense\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Advanced topics\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Advanced topics\",\n                \"description\": \"Learn about the advanced topics and inner workings of Yew!\"\n            },\n            \"items\": [\n                \"advanced-topics/how-it-works\",\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Struct Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"advanced-topics/struct-components/introduction\"\n                    },\n                    \"items\": [\n                        \"advanced-topics/struct-components/hoc\",\n                        \"advanced-topics/struct-components/lifecycle\",\n                        \"advanced-topics/struct-components/scope\",\n                        \"advanced-topics/struct-components/callbacks\",\n                        \"advanced-topics/struct-components/properties\",\n                        \"advanced-topics/struct-components/refs\"\n                    ]\n                },\n                \"advanced-topics/children\",\n                \"advanced-topics/optimizations\",\n                \"advanced-topics/portals\",\n                \"advanced-topics/server-side-rendering\",\n                \"advanced-topics/immutable\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"More\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Miscellaneous\"\n            },\n            \"items\": [\n                \"more/debugging\",\n                \"more/deployment\",\n                \"more/css\",\n                \"more/testing\",\n                \"more/roadmap\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Migration guides\",\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew\",\n                    \"items\": [\n                        \"migration-guides/yew/from-0_18_0-to-0_19_0\",\n                        \"migration-guides/yew/from-0_19_0-to-0_20_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-agent\",\n                    \"items\": [\n                        \"migration-guides/yew-agent/from-0_0_0-to-0_1_0\",\n                        \"migration-guides/yew-agent/from-0_1_0-to-0_2_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-router\",\n                    \"items\": [\n                        \"migration-guides/yew-router/from-0_15_0-to-0_16_0\",\n                        \"migration-guides/yew-router/from-0_16_0-to-0_17_0\"\n                    ]\n                }\n            ]\n        }\n    ],\n    \"api\": [\n        {\n            \"type\": \"autogenerated\",\n            \"dirName\": \"tutorial\"\n        }\n    ]\n}\n"
  },
  {
    "path": "website/versioned_sidebars/version-0.21-sidebars.json",
    "content": "{\n    \"docs\": [\n        {\n            \"type\": \"category\",\n            \"label\": \"Getting Started\",\n            \"link\": {\n                \"type\": \"doc\",\n                \"id\": \"getting-started/introduction\"\n            },\n            \"items\": [\n                \"getting-started/build-a-sample-app\",\n                \"getting-started/examples\",\n                \"getting-started/editor-setup\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Concepts\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Yew concepts\",\n                \"description\": \"Learn about the important Yew concepts!\"\n            },\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Using Basic Web Technologies In Yew\",\n                    \"link\": {\n                        \"type\": \"generated-index\",\n                        \"title\": \"Yew's Take on Basic Web Technologies\",\n                        \"description\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may needin one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\"\n                    },\n                    \"items\": [\n                        \"concepts/basic-web-technologies/html\",\n                        \"concepts/basic-web-technologies/css\",\n                        \"concepts/basic-web-technologies/js\",\n                        \"concepts/basic-web-technologies/wasm-bindgen\",\n                        \"concepts/basic-web-technologies/web-sys\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/function-components/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/function-components/properties\",\n                        \"concepts/function-components/callbacks\",\n                        \"concepts/function-components/children\",\n                        \"concepts/function-components/pure-components\",\n                        {\n                            \"type\": \"category\",\n                            \"label\": \"Hooks\",\n                            \"link\": {\n                                \"type\": \"doc\",\n                                \"id\": \"concepts/function-components/hooks/introduction\"\n                            },\n                            \"items\": [\n                                \"concepts/function-components/hooks/custom-hooks\"\n                            ]\n                        },\n                        \"concepts/function-components/node-refs\",\n                        \"concepts/function-components/state\",\n                        \"concepts/function-components/communication\",\n                        \"concepts/function-components/generics\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"HTML\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/html/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/html/components\",\n                        \"concepts/html/elements\",\n                        \"concepts/html/events\",\n                        \"concepts/html/classes\",\n                        \"concepts/html/fragments\",\n                        \"concepts/html/lists\",\n                        \"concepts/html/literals-and-expressions\",\n                        \"concepts/html/conditional-rendering\"\n                    ]\n                },\n                \"concepts/agents\",\n                \"concepts/contexts\",\n                \"concepts/router\",\n                \"concepts/suspense\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Advanced topics\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Advanced topics\",\n                \"description\": \"Learn about the advanced topics and inner workings of Yew!\"\n            },\n            \"items\": [\n                \"advanced-topics/how-it-works\",\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Struct Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"advanced-topics/struct-components/introduction\"\n                    },\n                    \"items\": [\n                        \"advanced-topics/struct-components/hoc\",\n                        \"advanced-topics/struct-components/lifecycle\",\n                        \"advanced-topics/struct-components/scope\",\n                        \"advanced-topics/struct-components/callbacks\",\n                        \"advanced-topics/struct-components/properties\",\n                        \"advanced-topics/struct-components/refs\"\n                    ]\n                },\n                \"advanced-topics/children\",\n                \"advanced-topics/optimizations\",\n                \"advanced-topics/portals\",\n                \"advanced-topics/server-side-rendering\",\n                \"advanced-topics/immutable\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"More\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Miscellaneous\"\n            },\n            \"items\": [\n                \"more/debugging\",\n                \"more/deployment\",\n                \"more/css\",\n                \"more/testing\",\n                \"more/roadmap\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Migration guides\",\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew\",\n                    \"items\": [\n                        \"migration-guides/yew/from-0_20_0-to-0_21_0\",\n                        \"migration-guides/yew/from-0_19_0-to-0_20_0\",\n                        \"migration-guides/yew/from-0_18_0-to-0_19_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-agent\",\n                    \"items\": [\n                        \"migration-guides/yew-agent/from-0_1_0-to-0_2_0\",\n                        \"migration-guides/yew-agent/from-0_0_0-to-0_1_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-router\",\n                    \"items\": [\n                        \"migration-guides/yew-router/from-0_16_0-to-0_17_0\",\n                        \"migration-guides/yew-router/from-0_15_0-to-0_16_0\"\n                    ]\n                }\n            ]\n        }\n    ],\n    \"api\": [\n        {\n            \"type\": \"autogenerated\",\n            \"dirName\": \"tutorial\"\n        }\n    ]\n}\n"
  },
  {
    "path": "website/versioned_sidebars/version-0.22-sidebars.json",
    "content": "{\n    \"docs\": [\n        {\n            \"type\": \"category\",\n            \"label\": \"Getting Started\",\n            \"link\": {\n                \"type\": \"doc\",\n                \"id\": \"getting-started/introduction\"\n            },\n            \"items\": [\n                \"getting-started/build-a-sample-app\",\n                \"getting-started/examples\",\n                \"getting-started/editor-setup\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Concepts\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Yew concepts\",\n                \"description\": \"Learn about the important Yew concepts!\"\n            },\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Using Basic Web Technologies In Yew\",\n                    \"link\": {\n                        \"type\": \"generated-index\",\n                        \"title\": \"Yew's Take on Basic Web Technologies\",\n                        \"description\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may needin one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\"\n                    },\n                    \"items\": [\n                        \"concepts/basic-web-technologies/html\",\n                        \"concepts/basic-web-technologies/css\",\n                        \"concepts/basic-web-technologies/js\",\n                        \"concepts/basic-web-technologies/wasm-bindgen\",\n                        \"concepts/basic-web-technologies/web-sys\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/function-components/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/function-components/properties\",\n                        \"concepts/function-components/callbacks\",\n                        \"concepts/function-components/children\",\n                        \"concepts/function-components/pure-components\",\n                        {\n                            \"type\": \"category\",\n                            \"label\": \"Hooks\",\n                            \"link\": {\n                                \"type\": \"doc\",\n                                \"id\": \"concepts/function-components/hooks/introduction\"\n                            },\n                            \"items\": [\n                                \"concepts/function-components/hooks/custom-hooks\"\n                            ]\n                        },\n                        \"concepts/function-components/node-refs\",\n                        \"concepts/function-components/state\",\n                        \"concepts/function-components/communication\",\n                        \"concepts/function-components/generics\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"HTML\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/html/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/html/components\",\n                        \"concepts/html/elements\",\n                        \"concepts/html/events\",\n                        \"concepts/html/classes\",\n                        \"concepts/html/fragments\",\n                        \"concepts/html/lists\",\n                        \"concepts/html/literals-and-expressions\",\n                        \"concepts/html/conditional-rendering\"\n                    ]\n                },\n                \"concepts/agents\",\n                \"concepts/contexts\",\n                \"concepts/router\",\n                \"concepts/suspense\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Advanced topics\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Advanced topics\",\n                \"description\": \"Learn about the advanced topics and inner workings of Yew!\"\n            },\n            \"items\": [\n                \"advanced-topics/how-it-works\",\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Struct Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"advanced-topics/struct-components/introduction\"\n                    },\n                    \"items\": [\n                        \"advanced-topics/struct-components/hoc\",\n                        \"advanced-topics/struct-components/lifecycle\",\n                        \"advanced-topics/struct-components/scope\",\n                        \"advanced-topics/struct-components/callbacks\",\n                        \"advanced-topics/struct-components/properties\",\n                        \"advanced-topics/struct-components/refs\"\n                    ]\n                },\n                \"advanced-topics/children\",\n                \"advanced-topics/optimizations\",\n                \"advanced-topics/portals\",\n                \"advanced-topics/server-side-rendering\",\n                \"advanced-topics/immutable\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"More\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Miscellaneous\"\n            },\n            \"items\": [\n                \"more/debugging\",\n                \"more/deployment\",\n                \"more/css\",\n                \"more/testing\",\n                \"more/roadmap\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Migration guides\",\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew\",\n                    \"items\": [\n                        \"migration-guides/yew/from-0_21_0-to-0_22_0\",\n                        \"migration-guides/yew/from-0_20_0-to-0_21_0\",\n                        \"migration-guides/yew/from-0_19_0-to-0_20_0\",\n                        \"migration-guides/yew/from-0_18_0-to-0_19_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-agent\",\n                    \"items\": [\n                        \"migration-guides/yew-agent/from-0_3_0-to-0_4_0\",\n                        \"migration-guides/yew-agent/from-0_1_0-to-0_2_0\",\n                        \"migration-guides/yew-agent/from-0_0_0-to-0_1_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-router\",\n                    \"items\": [\n                        \"migration-guides/yew-router/from-0_16_0-to-0_17_0\",\n                        \"migration-guides/yew-router/from-0_15_0-to-0_16_0\"\n                    ]\n                }\n            ]\n        }\n    ],\n    \"api\": [\n        {\n            \"type\": \"autogenerated\",\n            \"dirName\": \"tutorial\"\n        }\n    ]\n}\n"
  },
  {
    "path": "website/versioned_sidebars/version-0.23-sidebars.json",
    "content": "{\n    \"docs\": [\n        {\n            \"type\": \"category\",\n            \"label\": \"Getting Started\",\n            \"link\": {\n                \"type\": \"doc\",\n                \"id\": \"getting-started/introduction\"\n            },\n            \"items\": [\n                \"getting-started/build-a-sample-app\",\n                \"getting-started/examples\",\n                \"getting-started/editor-setup\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Concepts\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Yew concepts\",\n                \"description\": \"Learn about the important Yew concepts!\"\n            },\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Using Basic Web Technologies In Yew\",\n                    \"link\": {\n                        \"type\": \"generated-index\",\n                        \"title\": \"Yew's Take on Basic Web Technologies\",\n                        \"description\": \"Yew centrally operates on the idea of keeping everything that a reusable piece of UI may needin one place - rust files, while also keeping the underlying technology accessible where necessary. Explore further to fully grasp what we mean by these statements:\"\n                    },\n                    \"items\": [\n                        \"concepts/basic-web-technologies/html\",\n                        \"concepts/basic-web-technologies/css\",\n                        \"concepts/basic-web-technologies/js\",\n                        \"concepts/basic-web-technologies/wasm-bindgen\",\n                        \"concepts/basic-web-technologies/web-sys\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/function-components/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/function-components/properties\",\n                        \"concepts/function-components/callbacks\",\n                        \"concepts/function-components/children\",\n                        \"concepts/function-components/pure-components\",\n                        {\n                            \"type\": \"category\",\n                            \"label\": \"Hooks\",\n                            \"link\": {\n                                \"type\": \"doc\",\n                                \"id\": \"concepts/function-components/hooks/introduction\"\n                            },\n                            \"items\": [\n                                \"concepts/function-components/hooks/custom-hooks\"\n                            ]\n                        },\n                        \"concepts/function-components/node-refs\",\n                        \"concepts/function-components/state\",\n                        \"concepts/function-components/communication\",\n                        \"concepts/function-components/generics\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"HTML\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"concepts/html/introduction\"\n                    },\n                    \"items\": [\n                        \"concepts/html/components\",\n                        \"concepts/html/elements\",\n                        \"concepts/html/events\",\n                        \"concepts/html/classes\",\n                        \"concepts/html/fragments\",\n                        \"concepts/html/lists\",\n                        \"concepts/html/literals-and-expressions\",\n                        \"concepts/html/conditional-rendering\"\n                    ]\n                },\n                \"concepts/agents\",\n                \"concepts/contexts\",\n                \"concepts/router\",\n                \"concepts/suspense\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Advanced topics\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Advanced topics\",\n                \"description\": \"Learn about the advanced topics and inner workings of Yew!\"\n            },\n            \"items\": [\n                \"advanced-topics/how-it-works\",\n                {\n                    \"type\": \"category\",\n                    \"label\": \"Struct Components\",\n                    \"link\": {\n                        \"type\": \"doc\",\n                        \"id\": \"advanced-topics/struct-components/introduction\"\n                    },\n                    \"items\": [\n                        \"advanced-topics/struct-components/hoc\",\n                        \"advanced-topics/struct-components/lifecycle\",\n                        \"advanced-topics/struct-components/scope\",\n                        \"advanced-topics/struct-components/callbacks\",\n                        \"advanced-topics/struct-components/properties\",\n                        \"advanced-topics/struct-components/refs\"\n                    ]\n                },\n                \"advanced-topics/children\",\n                \"advanced-topics/optimizations\",\n                \"advanced-topics/portals\",\n                \"advanced-topics/server-side-rendering\",\n                \"advanced-topics/immutable\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"More\",\n            \"link\": {\n                \"type\": \"generated-index\",\n                \"title\": \"Miscellaneous\"\n            },\n            \"items\": [\n                \"more/debugging\",\n                \"more/deployment\",\n                \"more/css\",\n                \"more/testing\",\n                \"more/roadmap\"\n            ]\n        },\n        {\n            \"type\": \"category\",\n            \"label\": \"Migration guides\",\n            \"items\": [\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew\",\n                    \"items\": [\n                        \"migration-guides/yew/from-0_22_0-to-0_23_0\",\n                        \"migration-guides/yew/from-0_21_0-to-0_22_0\",\n                        \"migration-guides/yew/from-0_20_0-to-0_21_0\",\n                        \"migration-guides/yew/from-0_19_0-to-0_20_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-agent\",\n                    \"items\": [\n                        \"migration-guides/yew-agent/from-0_4_0-to-0_5_0\",\n                        \"migration-guides/yew-agent/from-0_3_0-to-0_4_0\",\n                        \"migration-guides/yew-agent/from-0_1_0-to-0_2_0\",\n                        \"migration-guides/yew-agent/from-0_0_0-to-0_1_0\"\n                    ]\n                },\n                {\n                    \"type\": \"category\",\n                    \"label\": \"yew-router\",\n                    \"items\": [\n                        \"migration-guides/yew-router/from-0_19_0-to-0_20_0\",\n                        \"migration-guides/yew-router/from-0_16_0-to-0_17_0\",\n                        \"migration-guides/yew-router/from-0_15_0-to-0_16_0\"\n                    ]\n                }\n            ]\n        }\n    ],\n    \"api\": [\n        {\n            \"type\": \"autogenerated\",\n            \"dirName\": \"tutorial\"\n        }\n    ]\n}\n"
  },
  {
    "path": "website/versions.json",
    "content": "[\"0.23\", \"0.22\", \"0.21\", \"0.20\"]\n"
  },
  {
    "path": "website/write-translations.js",
    "content": "const {\n    i18n: { locales },\n} = require('./docusaurus.config.js')\nconst util = require('util')\nconst exec = util.promisify(require('child_process').exec)\n\n/**\n * @param {string} locale\n */\nasync function writeTranslation(locale) {\n    // exec rejects when the subprocess exits with non-zero code\n    const { stdout, stderr } = await exec(\n        `npm run docusaurus -- write-translations --locale ${locale}`\n    )\n    console.log(stdout)\n    console.error(stderr)\n}\n\nasync function writeTranslations() {\n    for (const locale of locales.filter((locale) => locale !== 'en')) {\n        await writeTranslation(locale)\n    }\n}\n\nmodule.exports = writeTranslations\n\nif (require.main === module) {\n    writeTranslations().catch((e) => console.error(e))\n}\n"
  }
]