Pārlūkot izejas kodu

Merge branch 'master' into master

Jon Kelley 3 gadi atpakaļ
vecāks
revīzija
c4a19f71af
100 mainītis faili ar 4655 papildinājumiem un 556 dzēšanām
  1. 2 2
      .github/workflows/docs.yml
  2. 12 0
      .github/workflows/macos.yml
  3. 35 18
      .github/workflows/main.yml
  4. 12 0
      .github/workflows/windows.yml
  5. 4 0
      .vscode/spellright.dict
  6. 50 27
      Cargo.toml
  7. 11 33
      README.md
  8. 0 0
      benches/create.rs
  9. 0 0
      benches/jsframework.rs
  10. 220 0
      benches/tui_update.rs
  11. 2 0
      codecov.yml
  12. 1 0
      docs/cli/.gitignore
  13. 6 0
      docs/cli/book.toml
  14. 11 0
      docs/cli/src/SUMMARY.md
  15. 26 0
      docs/cli/src/cmd/README.md
  16. 47 0
      docs/cli/src/cmd/build.md
  17. 18 0
      docs/cli/src/cmd/clean.md
  18. 49 0
      docs/cli/src/cmd/serve.md
  19. 57 0
      docs/cli/src/cmd/translate.md
  20. 147 0
      docs/cli/src/configure.md
  21. 38 0
      docs/cli/src/creating.md
  22. 24 0
      docs/cli/src/installation.md
  23. 21 0
      docs/cli/src/introduction.md
  24. 1 0
      docs/fermi/.gitignore
  25. 6 0
      docs/fermi/book.toml
  26. 3 0
      docs/fermi/src/SUMMARY.md
  27. 1 0
      docs/fermi/src/chapter_1.md
  28. 10 10
      docs/guide/src/README.md
  29. 24 21
      docs/guide/src/ROADMAP.md
  30. 20 8
      docs/guide/src/SUMMARY.md
  31. 183 0
      docs/guide/src/async/coroutines.md
  32. 0 2
      docs/guide/src/async/fetching.md
  33. 88 6
      docs/guide/src/async/index.md
  34. 8 0
      docs/guide/src/async/loading_state.md
  35. 1 0
      docs/guide/src/async/sockets.md
  36. 85 0
      docs/guide/src/async/use_future.md
  37. 9 8
      docs/guide/src/components/component_children.md
  38. 13 13
      docs/guide/src/components/composing.md
  39. 43 11
      docs/guide/src/components/propsmacro.md
  40. 1 1
      docs/guide/src/elements/conditional_rendering.md
  41. 7 8
      docs/guide/src/elements/special_attributes.md
  42. 4 2
      docs/guide/src/elements/vnodes.md
  43. 14 9
      docs/guide/src/hello_world.md
  44. 47 0
      docs/guide/src/helpers/index.md
  45. 116 1
      docs/guide/src/interactivity/event_handlers.md
  46. 1 2
      docs/guide/src/interactivity/hooks.md
  47. 0 117
      docs/guide/src/interactivity/importanthooks.md
  48. 8 8
      docs/guide/src/interactivity/index.md
  49. 10 2
      docs/guide/src/interactivity/lifecycles.md
  50. 78 2
      docs/guide/src/interactivity/user_input.md
  51. 155 0
      docs/guide/src/interactivity/useref.md
  52. 114 0
      docs/guide/src/interactivity/usestate.md
  53. 7 1
      docs/guide/src/setup.md
  54. 1 0
      docs/guide/src/state/channels.md
  55. 148 2
      docs/guide/src/state/errorhandling.md
  56. 61 0
      docs/guide/src/state/fanout.md
  57. 110 0
      docs/guide/src/state/fermi.md
  58. 22 12
      docs/guide/src/state/index.md
  59. 128 2
      docs/guide/src/state/liftingstate.md
  60. 107 1
      docs/guide/src/state/localstate.md
  61. 86 0
      docs/guide/src/state/router.md
  62. 61 3
      docs/guide/src/state/sharedstate.md
  63. 367 0
      docs/posts/release-0-2-0.md
  64. 408 0
      docs/posts/release.md
  65. 6 5
      docs/reference/src/SUMMARY.md
  66. 1 1
      docs/reference/src/platforms/desktop.md
  67. 10 0
      docs/reference/src/platforms/index.md
  68. 4 4
      docs/reference/src/platforms/mobile.md
  69. 12 12
      docs/reference/src/platforms/ssr.md
  70. 100 0
      docs/reference/src/platforms/tui.md
  71. 2 2
      docs/reference/src/platforms/web.md
  72. 0 67
      docs/reference/src/tui/index.md
  73. 10 0
      docs/router/src/README.md
  74. 9 1
      docs/router/src/SUMMARY.md
  75. 0 3
      docs/router/src/chapter_1.md
  76. 201 0
      docs/router/src/guide/building-a-nest.md
  77. 95 0
      docs/router/src/guide/first-route.md
  78. 68 0
      docs/router/src/guide/getting-started.md
  79. 14 0
      docs/router/src/guide/index.md
  80. 51 0
      docs/router/src/guide/redirection-perfection.md
  81. 2 0
      docs/router/src/reference/index.md
  82. 10 8
      examples/README.md
  83. 411 0
      examples/all_css.rs
  84. 1 1
      examples/borrowed.rs
  85. 26 34
      examples/calculator.rs
  86. 3 3
      examples/core_reference/listener.rs
  87. 23 37
      examples/crm.rs
  88. 37 0
      examples/custom_html.rs
  89. 5 3
      examples/disabled.rs
  90. 21 30
      examples/dog_app.rs
  91. 22 0
      examples/error_handle.rs
  92. 25 0
      examples/eval.rs
  93. 26 0
      examples/events.rs
  94. 29 0
      examples/fermi.rs
  95. 1 1
      examples/file_explorer.rs
  96. 1 1
      examples/filedragdrop.rs
  97. 37 0
      examples/flat_router.rs
  98. 13 9
      examples/form.rs
  99. 2 2
      examples/framework_benchmark.rs
  100. 28 0
      examples/heavy_compute.rs

+ 2 - 2
.github/workflows/docs.yml

@@ -5,7 +5,6 @@ on:
     paths:
       - docs/**
       - .github/workflows/docs.yml
-  pull_request:
     branches:
       - master
 
@@ -25,7 +24,8 @@ jobs:
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
           cd reference && mdbook build -d ../nightly/reference && cd .. &&
-          cd router && mdbook build -d ../nightly/router  && cd ..
+          cd router && mdbook build -d ../nightly/router  && cd .. &&
+          cd cli && mdbook build -d ../nightly/cli  && cd ..
 
       - name: Deploy 🚀
         uses: JamesIves/github-pages-deploy-action@v4.2.3

+ 12 - 0
.github/workflows/macos.yml

@@ -2,6 +2,8 @@ name: macOS tests
 
 on:
   push:
+    branches:
+      - master
     paths:
       - packages/**
       - examples/**
@@ -9,12 +11,22 @@ on:
       - .github/**
       - lib.rs
       - Cargo.toml
+
   pull_request:
+    types: [opened, synchronize, reopened, ready_for_review]
     branches:
       - master
+    paths:
+      - packages/**
+      - examples/**
+      - src/**
+      - .github/**
+      - lib.rs
+      - Cargo.toml
 
 jobs:
   test:
+    if: github.event.pull_request.draft == false
     name: Test Suite
     runs-on: macos-latest
     steps:

+ 35 - 18
.github/workflows/main.yml

@@ -2,6 +2,8 @@ name: Rust CI
 
 on:
   push:
+    branches:
+      - master
     paths:
       - packages/**
       - examples/**
@@ -9,12 +11,22 @@ on:
       - .github/**
       - lib.rs
       - Cargo.toml
+
   pull_request:
+    types: [opened, synchronize, reopened, ready_for_review]
     branches:
       - master
+    paths:
+      - packages/**
+      - examples/**
+      - src/**
+      - .github/**
+      - lib.rs
+      - Cargo.toml
 
 jobs:
   check:
+    if: github.event.pull_request.draft == false
     name: Check
     runs-on: ubuntu-latest
     steps:
@@ -32,6 +44,7 @@ jobs:
           command: check
 
   test:
+    if: github.event.pull_request.draft == false
     name: Test Suite
     runs-on: ubuntu-latest
     steps:
@@ -53,6 +66,7 @@ jobs:
           args: tests
 
   fmt:
+    if: github.event.pull_request.draft == false
     name: Rustfmt
     runs-on: ubuntu-latest
     steps:
@@ -70,6 +84,7 @@ jobs:
           args: --all -- --check
 
   clippy:
+    if: github.event.pull_request.draft == false
     name: Clippy
     runs-on: ubuntu-latest
     steps:
@@ -88,21 +103,23 @@ jobs:
           command: clippy
           args: -- -D warnings
 
-  coverage:
-    name: Coverage
-    runs-on: ubuntu-latest
-    container:
-      image: xd009642/tarpaulin:develop-nightly
-      options: --security-opt seccomp=unconfined
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v2
-      - name: Generate code coverage
-        run: |
-          apt-get update &&\
-          apt install libwebkit2gtk-4.0-dev libappindicator3-dev libgtk-3-dev -y &&\
-          cargo +nightly tarpaulin --verbose --tests --all-features --workspace --timeout 120 --out Xml
-      - name: Upload to codecov.io
-        uses: codecov/codecov-action@v2
-        with:
-          fail_ci_if_error: false
+  # Coverage is disabled until we can fix it
+  # coverage:
+  #   name: Coverage
+  #   runs-on: ubuntu-latest
+  #   container:
+  #     image: xd009642/tarpaulin:develop-nightly
+  #     options: --security-opt seccomp=unconfined
+  #   steps:
+  #     - name: Checkout repository
+  #       uses: actions/checkout@v2
+  #     - name: Generate code coverage
+  #       run: |
+  #         apt-get update &&\
+  #         apt-get install build-essential &&\
+  #         apt install libwebkit2gtk-4.0-dev libappindicator3-dev libgtk-3-dev -y &&\
+  #         cargo +nightly tarpaulin --verbose --all-features --workspace --timeout 120 --out Xml
+  #     - name: Upload to codecov.io
+  #       uses: codecov/codecov-action@v2
+  #       with:
+  #         fail_ci_if_error: false

+ 12 - 0
.github/workflows/windows.yml

@@ -2,6 +2,8 @@ name: windows
 
 on:
   push:
+    branches:
+      - master
     paths:
       - packages/**
       - examples/**
@@ -9,12 +11,22 @@ on:
       - .github/**
       - lib.rs
       - Cargo.toml
+
   pull_request:
+    types: [opened, synchronize, reopened, ready_for_review]
     branches:
       - master
+    paths:
+      - packages/**
+      - examples/**
+      - src/**
+      - .github/**
+      - lib.rs
+      - Cargo.toml
 
 jobs:
   test:
+    if: github.event.pull_request.draft == false
     runs-on: windows-latest
     name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
     env:

+ 4 - 0
.vscode/spellright.dict

@@ -79,3 +79,7 @@ clonable
 oninput
 Webview
 idanarye
+Katex
+mrxiaozhuox
+Fruitie
+Vercel

+ 50 - 27
Cargo.toml

@@ -1,29 +1,36 @@
 [package]
 name = "dioxus"
-version = "0.1.8"
+version = "0.2.3"
 authors = ["Jonathan Kelley"]
-edition = "2018"
+edition = "2021"
 description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/DioxusLabs/dioxus/"
 homepage = "https://dioxuslabs.com"
 documentation = "https://dioxuslabs.com"
 keywords = ["dom", "ui", "gui", "react", "wasm"]
+rust-version = "1.56.0"
 
 [dependencies]
-dioxus-core = { path = "./packages/core", version = "^0.1.9" }
-dioxus-html = { path = "./packages/html", version = "^0.1.6", optional = true }
-dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.7", optional = true }
-dioxus-hooks = { path = "./packages/hooks", version = "^0.1.7", optional = true }
+dioxus-core = { path = "./packages/core", version = "^0.2.0" }
+dioxus-html = { path = "./packages/html", version = "^0.2.0", optional = true }
+dioxus-core-macro = { path = "./packages/core-macro", version = "^0.2.0", optional = true }
+dioxus-hooks = { path = "./packages/hooks", version = "^0.2.0", optional = true }
+fermi = { path = "./packages/fermi", version = "^0.2.0", optional = true }
 
-dioxus-web = { path = "./packages/web", version = "^0.0.5", optional = true }
-dioxus-desktop = { path = "./packages/desktop", version = "^0.1.6", optional = true }
-dioxus-ssr = { path = "./packages/ssr", version = "^0.1.3", optional = true }
+dioxus-web = { path = "./packages/web", version = "^0.2.0", optional = true }
+dioxus-desktop = { path = "./packages/desktop", version = "^0.2.2", optional = true }
+dioxus-ssr = { path = "./packages/ssr", version = "^0.2.0", optional = true }
 
-dioxus-router = { path = "./packages/router", version = "^0.1.1", optional = true }
-dioxus-mobile = { path = "./packages/mobile", version = "^0.0.3", optional = true }
-dioxus-interpreter-js = { path = "./packages/interpreter", version = "^0.0.0", optional = true }
-# dioxus-liveview = { path = "./packages/liveview", optional = true }
+dioxus-router = { path = "./packages/router", version = "^0.2.1", optional = true }
+dioxus-interpreter-js = { path = "./packages/interpreter", version = "^0.2.0", optional = true }
+dioxus-tui = { path = "./packages/tui", version = "^0.2.0", optional = true }
+
+dioxus-liveview = { path = "./packages/liveview", optional = true }
+
+# dioxus-mobile = { path = "./packages/mobile", version = "^0.2.0", optional = true }
+# dioxus-rsx = { path = "./packages/rsx", optional = true }
+# macro = ["dioxus-core-macro", "dioxus-rsx"]
 
 [features]
 default = ["macro", "hooks", "html"]
@@ -32,15 +39,12 @@ macro = ["dioxus-core-macro"]
 hooks = ["dioxus-hooks"]
 html = ["dioxus-html"]
 ssr = ["dioxus-ssr"]
-web = ["dioxus-web"]
+web = ["dioxus-web", "dioxus-router/web"]
 desktop = ["dioxus-desktop"]
+ayatana = ["dioxus-desktop/ayatana"]
 router = ["dioxus-router"]
-
-# "dioxus-router/web"
-# "dioxus-router/desktop"
-# desktop = ["dioxus-desktop", "dioxus-router/desktop"]
-# mobile = ["dioxus-mobile"]
-# liveview = ["dioxus-liveview"]
+tui = ["dioxus-tui"]
+liveview = ["dioxus-liveview"]
 
 
 [workspace]
@@ -54,18 +58,37 @@ members = [
     "packages/desktop",
     "packages/mobile",
     "packages/interpreter",
+    "packages/fermi",
+    "packages/tui",
+    "packages/liveview",
 ]
 
 [dev-dependencies]
-futures-util = "0.3.17"
+futures-util = "0.3.21"
 log = "0.4.14"
 num-format = "0.4.0"
 separator = "0.4.1"
-serde = { version = "1.0.131", features = ["derive"] }
+serde = { version = "1.0.136", features = ["derive"] }
 im-rc = "15.0.0"
-anyhow = "1.0.51"
-serde_json = "1.0.73"
+anyhow = "1.0.53"
+serde_json = "1.0.79"
 rand = { version = "0.8.4", features = ["small_rng"] }
-tokio = { version = "1.14.0", features = ["full"] }
-reqwest = { version = "0.11.8", features = ["json"] }
-dioxus = { path = ".", features = ["desktop", "ssr", "router"] }
+tokio = { version = "1.16.1", features = ["full"] }
+reqwest = { version = "0.11.9", features = ["json"] }
+dioxus = { path = ".", features = ["desktop", "ssr", "router", "fermi", "tui"] }
+fern = { version = "0.6.0", features = ["colored"] }
+criterion = "0.3.5"
+thiserror = "1.0.30"
+env_logger = "0.9.0"
+
+[[bench]]
+name = "create"
+harness = false
+
+[[bench]]
+name = "jsframework"
+harness = false
+
+[[bench]]
+name = "tui_update"
+harness = false

+ 11 - 33
README.md

@@ -1,8 +1,5 @@
 <div align="center">
   <h1>Dioxus</h1>
-  <p>
-    <strong>Frontend that scales.</strong>
-  </p>
 </div>
 
 <div align="center">
@@ -45,37 +42,30 @@
     <span> | </span>
     <a href="https://github.com/DioxusLabs/example-projects"> Examples </a>
     <span> | </span>
-    <a href="https://dioxuslabs.com/guide"> Guide (0.1.8) </a>
-    <span> | </span>
-    <a href="https://dioxuslabs.com/nightly/guide"> Guide (Master) </a>
-  </h3>
-</div>
-
-<div align="center">
-  <h4>
-    <a href="https://github.com/DioxusLabs/dioxus/blob/master/README.md"> English </a>
+    <a href="https://dioxuslabs.com/guide"> Guide </a>
     <span> | </span>
     <a href="https://github.com/DioxusLabs/dioxus/blob/master/notes/README/ZH_CN.md"> 中文 </a>
   </h3>
 </div>
 
+
 <br/>
 
 Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust.
 
 ```rust
 fn app(cx: Scope) -> Element {
-    let (count, set_count) = use_state(&cx, || 0);
+    let mut count = use_state(&cx, || 0);
 
-    cx.render(rsx!(
+    cx.render(rsx! {
         h1 { "High-Five counter: {count}" }
-        button { onclick: move |_| set_count(count + 1), "Up high!" }
-        button { onclick: move |_| set_count(count - 1), "Down low!" }
-    ))
+        button { onclick: move |_| count += 1, "Up high!" }
+        button { onclick: move |_| count -= 1, "Down low!" }
+    })
 }
 ```
 
-Dioxus can be used to deliver webapps, desktop apps, static sites, liveview apps, mobile apps (WIP), and more. At its core, Dioxus is entirely renderer agnostic and has great documentation for creating new renderers for any platform.
+Dioxus can be used to deliver webapps, desktop apps, static sites, mobile apps, TUI apps, liveview apps, and more. Dioxus is entirely renderer agnostic and can be used as platform for any renderer.
 
 If you know React, then you already know Dioxus.
 
@@ -87,15 +77,6 @@ If you know React, then you already know Dioxus.
 - Multi-channel asynchronous scheduler for first-class async support.
 - And more! Read the [full release post](https://dioxuslabs.com/blog/introducing-dioxus/).
 
-
-### Examples
-
-All examples in this repo are desktop apps. To run an example, simply clone this repo and use `cargo run --example XYZ`
-
-```
-cargo run --example EXAMPLE
-```
-
 ## Get Started with...
 
 <table style="width:100%" align="center">
@@ -119,13 +100,10 @@ cargo run --example EXAMPLE
 
 See the [awesome-dioxus](https://github.com/DioxusLabs/awesome-dioxus) page for a curated list of content in the Dioxus Ecosystem.
 
-
 ## Why Dioxus and why Rust?
 
 TypeScript is a fantastic addition to JavaScript, but it's still fundamentally JavaScript. TS code runs slightly slower, has tons of configuration options, and not every package is properly typed.
 
-In contrast, Dioxus is written in Rust - which is almost like "TypeScript on steroids".
-
 By using Rust, we gain:
 
 - Static types for *every* library
@@ -160,9 +138,9 @@ You shouldn't use Dioxus if:
 ## Comparison with other Rust UI frameworks
 Dioxus primarily emphasizes **developer experience** and **familiarity with React principles**.
 
-- [Yew](https://github.com/yewstack/yew): prefers the elm pattern instead of React-hooks, no borrowed props, supports SSR (no hydration).
+- [Yew](https://github.com/yewstack/yew): prefers the elm pattern instead, no borrowed props, supports SSR (no hydration), no direct desktop/mobile support.
 - [Percy](https://github.com/chinedufn/percy): Supports SSR but with less emphasis on state management and event handling.
-- [Sycamore](https://github.com/sycamore-rs/sycamore): VDOM-less using fine-grained reactivity, but lacking in ergonomics.
+- [Sycamore](https://github.com/sycamore-rs/sycamore): VDOM-less using fine-grained reactivity, but no direct support for desktop/mobile.
 - [Dominator](https://github.com/Pauan/rust-dominator): Signal-based zero-cost alternative, less emphasis on community and docs.
 - [Azul](https://azul.rs): Fully native HTML/CSS renderer for desktop applications, no support for web/ssr
 
@@ -197,7 +175,7 @@ Want to jump in and help build the future of Rust frontend? There's plenty of pl
 
 This project is licensed under the [MIT license].
 
-[MIT license]: https://github.com/dioxuslabs/dioxus/blob/master/LICENSE
+[MIT license]: https://github.com/DioxusLabs/dioxus/blob/master/LICENSE-MIT
 
 ### Contribution
 

+ 0 - 0
packages/core/benches/create.rs → benches/create.rs


+ 0 - 0
packages/core/benches/jsframework.rs → benches/jsframework.rs


+ 220 - 0
benches/tui_update.rs

@@ -0,0 +1,220 @@
+use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
+use dioxus::prelude::*;
+use dioxus_tui::{Config, TuiContext};
+
+criterion_group!(mbenches, tui_update);
+criterion_main!(mbenches);
+
+/// This benchmarks the cache performance of the TUI for small edits by changing one box at a time.
+fn tui_update(c: &mut Criterion) {
+    let mut group = c.benchmark_group("Update boxes");
+
+    // We can also use loops to define multiple benchmarks, even over multiple dimensions.
+    for size in 1..=8u32 {
+        let parameter_string = format!("{}", (3 * size).pow(2));
+        group.bench_with_input(
+            BenchmarkId::new("size", parameter_string),
+            &size,
+            |b, size| {
+                b.iter(|| match size {
+                    1 => dioxus::tui::launch_cfg(app3, Config::default().with_headless()),
+                    2 => dioxus::tui::launch_cfg(app6, Config::default().with_headless()),
+                    3 => dioxus::tui::launch_cfg(app9, Config::default().with_headless()),
+                    4 => dioxus::tui::launch_cfg(app12, Config::default().with_headless()),
+                    5 => dioxus::tui::launch_cfg(app15, Config::default().with_headless()),
+                    6 => dioxus::tui::launch_cfg(app18, Config::default().with_headless()),
+                    7 => dioxus::tui::launch_cfg(app21, Config::default().with_headless()),
+                    8 => dioxus::tui::launch_cfg(app24, Config::default().with_headless()),
+                    _ => (),
+                })
+            },
+        );
+    }
+}
+
+#[derive(Props, PartialEq)]
+struct BoxProps {
+    x: usize,
+    y: usize,
+    hue: f32,
+    alpha: f32,
+}
+#[allow(non_snake_case)]
+fn Box(cx: Scope<BoxProps>) -> Element {
+    let count = use_state(&cx, || 0);
+
+    let x = cx.props.x * 2;
+    let y = cx.props.y * 2;
+    let hue = cx.props.hue;
+    let display_hue = cx.props.hue as u32 / 10;
+    let count = count.get();
+    let alpha = cx.props.alpha + (count % 100) as f32;
+
+    cx.render(rsx! {
+        div {
+            left: "{x}%",
+            top: "{y}%",
+            width: "100%",
+            height: "100%",
+            background_color: "hsl({hue}, 100%, 50%, {alpha}%)",
+            align_items: "center",
+            p{"{display_hue:03}"}
+        }
+    })
+}
+
+#[derive(Props, PartialEq)]
+struct GridProps {
+    size: usize,
+}
+#[allow(non_snake_case)]
+fn Grid(cx: Scope<GridProps>) -> Element {
+    let size = cx.props.size;
+    let count = use_state(&cx, || 0);
+    let counts = use_ref(&cx, || vec![0; size * size]);
+
+    let ctx: TuiContext = cx.consume_context().unwrap();
+    if *count.get() + 1 >= (size * size) {
+        ctx.quit();
+    } else {
+        counts.with_mut(|c| {
+            let i = *count.current();
+            c[i] += 1;
+            c[i] = c[i] % 360;
+        });
+        count.with_mut(|i| {
+            *i += 1;
+            *i = *i % (size * size);
+        });
+    }
+
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            flex_direction: "column",
+            (0..size).map(|x|
+                    {
+                    cx.render(rsx! {
+                        div{
+                            width: "100%",
+                            height: "100%",
+                            flex_direction: "row",
+                            (0..size).map(|y|
+                                {
+                                    let alpha = y as f32*100.0/size as f32 + counts.read()[x*size + y] as f32;
+                                    let key = format!("{}-{}", x, y);
+                                    cx.render(rsx! {
+                                        Box{
+                                            x: x,
+                                            y: y,
+                                            alpha: 100.0,
+                                            hue: alpha,
+                                            key: "{key}",
+                                        }
+                                    })
+                                }
+                            )
+                        }
+                    })
+                }
+            )
+        }
+    })
+}
+
+fn app3(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 3,
+            }
+        }
+    })
+}
+
+fn app6(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 6,
+            }
+        }
+    })
+}
+
+fn app9(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 9,
+            }
+        }
+    })
+}
+
+fn app12(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 12,
+            }
+        }
+    })
+}
+
+fn app15(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 15,
+            }
+        }
+    })
+}
+
+fn app18(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 18,
+            }
+        }
+    })
+}
+
+fn app21(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 21,
+            }
+        }
+    })
+}
+
+fn app24(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 24,
+            }
+        }
+    })
+}

+ 2 - 0
codecov.yml

@@ -0,0 +1,2 @@
+comment: false
+fail_ci_if_error: false

+ 1 - 0
docs/cli/.gitignore

@@ -0,0 +1 @@
+book

+ 6 - 0
docs/cli/book.toml

@@ -0,0 +1,6 @@
+[book]
+authors = ["YuKun Liu"]
+language = "en"
+multilingual = false
+src = "src"
+title = "Dioxus Cli"

+ 11 - 0
docs/cli/src/SUMMARY.md

@@ -0,0 +1,11 @@
+# Summary
+
+- [Introduction](./introduction.md)
+- [Installation](./installation.md)
+- [Create a Project](./creating.md)
+- [Configure Project](./configure.md)
+- [Commands](./cmd/README.md)
+  - [Build](./cmd/build.md)
+  - [Serve](./cmd/serve.md)
+  - [Clean](./cmd/clean.md)
+  - [Translate](./cmd/translate.md)

+ 26 - 0
docs/cli/src/cmd/README.md

@@ -0,0 +1,26 @@
+# Commands
+
+In this chapter we will introduce all `dioxus-cli` commands.
+
+> you can also use `dioxus --help` to get cli help info.
+
+```
+dioxus 
+Build, bundle, & ship your Dioxus app
+
+USAGE:
+    dioxus [OPTIONS] <SUBCOMMAND>
+
+OPTIONS:
+    -h, --help    Print help information
+    -v            Enable verbose logging
+
+SUBCOMMANDS:
+    build        Build the Rust WASM app and all of its assets
+    clean        Clean output artifacts
+    config       Dioxus config file controls
+    create       Init a new project for Dioxus
+    help         Print this message or the help of the given subcommand(s)
+    serve        Build, watch & serve the Rust WASM app and all of its assets
+    translate    Translate some source file into Dioxus code
+```

+ 47 - 0
docs/cli/src/cmd/build.md

@@ -0,0 +1,47 @@
+# Build
+
+The `dioxus build` command can help you `pack & build` a dioxus project.
+
+```
+dioxus-build 
+Build the Rust WASM app and all of its assets
+
+USAGE:
+    dioxus build [OPTIONS]
+
+OPTIONS:
+        --example <EXAMPLE>      [default: ""]
+        --platform <PLATFORM>    [default: "default_platform"]
+        --release                [default: false]
+```
+
+You can use this command to build project to `out_dir` :
+
+```
+dioxus build --release
+```
+
+## Target platform
+
+Use option `platform` choose build target platform:
+
+```
+# for desktop project
+dioxus build --platform desktop
+```
+
+`platform` only supports `desktop` & `web`.
+
+```
+# for web project
+dioxus build --platform web
+```
+
+## Build Example
+
+You can use `--example {name}` to build a example code.
+
+```
+# build `example/test` code
+dioxus build --exmaple test
+```

+ 18 - 0
docs/cli/src/cmd/clean.md

@@ -0,0 +1,18 @@
+# Clean
+
+`dioxus clean` will call `target clean` and remove `out_dir` directory.
+
+```
+dioxus-clean 
+Clean output artifacts
+
+USAGE:
+    dioxus clean
+```
+
+you can use this command to clean all build cache and the `out_dir` content.
+
+```
+dioxus clean
+```
+

+ 49 - 0
docs/cli/src/cmd/serve.md

@@ -0,0 +1,49 @@
+# Serve
+
+The `dioxus serve` can start a dev server (include hot-reload tool) to run the project.
+
+```
+dioxus-serve 
+Build, watch & serve the Rust WASM app and all of its assets
+
+USAGE:
+    dioxus serve [OPTIONS]
+
+OPTIONS:
+        --example <EXAMPLE>      [default: ""]
+        --platform <PLATFORM>    [default: "default_platform"]
+        --release                [default: false]
+```
+
+You can use this command to build project and start a `dev server` :
+
+```
+dioxus serve
+```
+
+## Target platform
+
+Use option `platform` choose build target platform:
+
+```
+# for desktop project
+dioxus serve --platform desktop
+```
+
+`platform` only supports `desktop` & `web`.
+
+`dev-server` only for `web` project.
+
+```
+# for web project
+dioxus serve --platform web
+```
+
+## Serve Example
+
+You can use `--example {name}` to start a example code.
+
+```
+# build `example/test` code
+dioxus serve --exmaple test
+```

+ 57 - 0
docs/cli/src/cmd/translate.md

@@ -0,0 +1,57 @@
+# Translate
+
+`dioxus translate` can translate some source file into Dioxus code.
+
+```
+dioxus-translate 
+Translate some source file into Dioxus code
+
+USAGE:
+    dioxus translate [OPTIONS] [OUTPUT]
+
+ARGS:
+    <OUTPUT>    Output file, stdout if not present
+
+OPTIONS:
+    -c, --component      Activate debug mode
+    -f, --file <FILE>    Input file
+```
+
+## Translate HTML to stdout
+
+```
+dioxus transtale --file ./index.html
+```
+
+## Output in a file
+
+```
+dioxus translate --component --file ./index.html component.rsx
+```
+
+set `component` flag will wrap `dioxus rsx` code in a component function.
+
+## Example
+
+```html
+<div>
+    <h1> Hello World </h1>
+    <a href="https://dioxuslabs.com/">Link</a>
+</div>
+```
+
+Translate HTML to Dioxus component code.
+
+```rust
+fn component(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            h1 { "Hello World" },
+            a {
+                href: "https://dioxuslabs.com/",
+                "Link"
+            }
+        }
+    })
+}
+```

+ 147 - 0
docs/cli/src/configure.md

@@ -0,0 +1,147 @@
+# Configure Project
+
+This chapter will introduce `Dioxus.toml` and anatomy the config file.
+
+## Structure
+
+We use `toml` to define some info for `dioxus` project.
+
+### Application
+
+1. ***name*** - project name & title
+2. ***default_platform*** - which platform target for this project.
+   ```
+   # current support: web, desktop
+   # default: web
+   default_platform = "web"
+   ```
+   change this to `desktop`, the `dioxus build & serve` will default build desktop app.
+3. ***out_dir*** - which directory to put the output file; use `dioxus build & service`, the output will put at this directory, and the `assets` will be also copy to here.
+    ```
+    out_dir = "dist"
+    ```
+4. ***asset_dir*** - which direcotry to put your `static, assets` file, cli will automatic copy all file to `out_dir`, so you can put some resource file in there, like `CSS, JS, Image` file.
+   ```
+   asset_dir = "public"
+   ```
+
+### Web.App
+
+Web platform application config:
+
+1. ***title*** - this value will display on the web page title. like `<title></title>` tag.
+   ```
+   # HTML title tag content
+   title = "dioxus app | ⛺"
+   ```
+
+### Web.Watcher
+
+Web platform `dev-server` watcher config:
+
+1. ***reload_html*** - a boolean value; when watcher trigger, regenerate `index.html` file.
+   ```
+   # when watcher trigger, regenerate the `index.html`
+   reload_html = true
+   ```
+2. ***watch_path*** - which files & directories will be watcher monitoring.
+   ```
+   watch_path = ["src", "public"]
+   ```
+
+### Web.Resource
+
+Include some `CSS Javascript` resources into html file.
+
+1. ***style*** - include some style(CSS) file into html.
+   ```
+   style = [
+      # include from public_dir.
+      "./assets/style.css",
+      # or some asset from online cdn.
+      "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
+   ]
+   ```
+2. ***script*** - include some script(JS) file into html.
+    ```
+    style = [
+        # include from public_dir.
+        "./assets/index.js",
+        # or some asset from online cdn.
+        "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
+    ]
+   ```
+
+### Web.Resource.Dev
+
+Only include resources at `Dev` mode.
+
+1. ***style*** - include some style(CSS) file into html.
+   ```
+   style = [
+      # include from public_dir.
+      "./assets/style.css",
+      # or some asset from online cdn.
+      "https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.css"
+   ]
+   ```
+2. ***script*** - include some script(JS) file into html.
+    ```
+    style = [
+        # include from public_dir.
+        "./assets/index.js",
+        # or some asset from online cdn.
+        "https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.js"
+    ]
+   ```
+
+## Config example
+
+```toml
+[application]
+
+# App (Project) Name
+name = "{{project-name}}"
+
+# Dioxus App Default Platform
+# desktop, web, mobile, ssr
+default_platform = "web"
+
+# `build` & `serve` dist path
+out_dir = "dist"
+
+# resource (public) file folder
+asset_dir = "public"
+
+[web.app]
+
+# HTML title tag content
+title = "dioxus | ⛺"
+
+[web.watcher]
+
+# when watcher trigger, regenerate the `index.html`
+reload_html = true
+
+# which files or dirs will be watcher monitoring
+watch_path = ["src", "public"]
+
+# include `assets` in web platform
+[web.resource]
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+
+[web.resource.dev]
+
+# serve: [dev-server] only
+
+# CSS style file
+style = []
+
+# Javascript code file
+script = []
+```

+ 38 - 0
docs/cli/src/creating.md

@@ -0,0 +1,38 @@
+# Create a Project
+
+Once you have the Dioxus CLI tool installed, you can use it to create dioxus project.
+
+## Initializing a default project
+
+The `dioxus create` command will create a new directory containing a project template.
+```
+dioxus create hello-dioxus
+```
+
+It will clone a default template from github template: [DioxusLabs/dioxus-template](https://github.com/DioxusLabs/dioxus-template)
+
+> This default template is use for `web` platform application.
+
+then you can change the current directory in to the project:
+
+```
+cd hello-dioxus
+```
+
+> Make sure `wasm32 target` is installed before running the Web project.
+
+now we can create a `dev server` to display the project:
+
+```
+dioxus serve
+```
+
+by default, the dioxus dev server will running at: [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/)
+
+## Initalizing from other repository
+
+you can assign which repository you want to create:
+
+```
+dioxus init hello-dioxus --template=gh:dioxuslabs/dioxus-template
+```

+ 24 - 0
docs/cli/src/installation.md

@@ -0,0 +1,24 @@
+# Installation
+
+There are multiple ways to install the Dioxus CLI tool. Choose any one of the methods below that best suit your needs.
+
+## Install from latest master version
+
+We suggest you use `github master` version to install it now.
+
+We have not yet released the latest version to `crates.io`
+
+```
+cargo install --git https://github.com/Dioxuslabs/cli
+```
+
+This will automatically download `Dioxus-CLI` source from github master branch,
+and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
+
+## Install from `crates.io` version
+
+```
+cargo install dioxus-cli
+```
+
+Make sure to add the Cargo bin directory to your `PATH`.

+ 21 - 0
docs/cli/src/introduction.md

@@ -0,0 +1,21 @@
+# Introduction
+
+📦✨ **Dioxus-Cli** is a tool to help get dioxus projects off the ground.
+
+![dioxus-logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png)
+
+It includes `dev server`, `hot reload` and some `quick command` to help you use dioxus.
+
+## Features
+
+- [x] `html` to `rsx` conversion tool
+- [x] hot reload for `web` platform
+- [x] create dioxus project from `git` repo
+- [x] build & pack dioxus project
+- [ ] autoformat dioxus `rsx` code
+
+## Contributors
+
+Contributors to this guide:
+
+- [mrxiaozhuox](https://github.com/mrxiaozhuox)

+ 1 - 0
docs/fermi/.gitignore

@@ -0,0 +1 @@
+book

+ 6 - 0
docs/fermi/book.toml

@@ -0,0 +1,6 @@
+[book]
+authors = ["Jonathan Kelley"]
+language = "en"
+multilingual = false
+src = "src"
+title = "Fermi Guide"

+ 3 - 0
docs/fermi/src/SUMMARY.md

@@ -0,0 +1,3 @@
+# Summary
+
+- [Chapter 1](./chapter_1.md)

+ 1 - 0
docs/fermi/src/chapter_1.md

@@ -0,0 +1 @@
+# Chapter 1

+ 10 - 10
docs/guide/src/README.md

@@ -2,23 +2,23 @@
 
 ![dioxuslogo](./images/dioxuslogo_full.png)
 
-**Dioxus** is a framework and ecosystem for building fast, scalable, and robust user interfaces with the Rust programming language. This guide will help you get started with Dioxus running on the Web, Desktop, Mobile, and more.
+**Dioxus** is a library for building fast, scalable, and robust user interfaces with the Rust programming language. This guide will help you get started with Dioxus running on the Web, Desktop, Mobile, and more.
 
 ```rust
 fn app(cx: Scope) -> Element {
-    let (count, set_count) = use_state(&cx, || 0);
+    let mut count = use_state(&cx, || 0);
 
     cx.render(rsx!(
         h1 { "High-Five counter: {count}" }
-        button { onclick: move |_| set_count(count + 1), "Up high!" }
-        button { onclick: move |_| set_count(count - 1), "Down low!" }
+        button { onclick: move |_| count += 1, "Up high!" }
+        button { onclick: move |_| count -= 1, "Down low!" }
     ))
 };
 ```
 
 In general, Dioxus and React share many functional similarities. If this guide is lacking in any general concept or an error message is confusing, React's documentation might be more helpful. We are dedicated to providing a *familiar* toolkit for UI in Rust, so we've chosen to follow in the footsteps of popular UI frameworks (React, Redux, etc). If you know React, then you already know Dioxus. If you don't know either, this guide will still help you!
 
-> This is an introduction book! For advanced topics, check out the [Reference](https://dioxuslabs.com/reference) instead.
+> This is an introduction book! For advanced topics, check out the [Reference](/reference) instead.
 
 ## Multiplatform
 
@@ -37,7 +37,7 @@ The Web is the best-supported target platform for Dioxus. To run on the Web, you
 
 Because the web is a fairly mature platform, we expect there to be very little API churn for web-based features.
 
-[Jump to the getting started guide for the web.]()
+[Jump to the getting started guide for the web.](/reference/platforms/web)
 
 Examples:
 - [TodoMVC](https://github.com/DioxusLabs/example-projects/tree/master/todomvc)
@@ -55,7 +55,7 @@ For rendering statically to an `.html` file or from a WebServer, then you'll wan
 let contents = dioxus::ssr::render_vdom(&dom);
 ```
 
-[Jump to the getting started guide for SSR.]()
+[Jump to the getting started guide for SSR.](/reference/platforms/ssr)
 
 Examples:
 - [Example DocSite](https://github.com/dioxusLabs/docsite)
@@ -68,13 +68,13 @@ The desktop is a powerful target for Dioxus, but is currently limited in capabil
 
 Desktop APIs will likely be in flux as we figure out better patterns than our ElectronJS counterpart.
 
-[Jump to the getting started guide for Desktop.]()
+[Jump to the getting started guide for Desktop.](/reference/platforms/desktop)
 
 Examples:
 - [File explorer](https://github.com/dioxusLabs/file-explorer/)
 - [WiFi scanner](https://github.com/DioxusLabs/example-projects/blob/master/wifi-scanner)
 
-[![File ExplorerExample](https://github.com/DioxusLabs/file-explorer-example/raw/master/image.png)](https://github.com/dioxusLabs/file-explorer/)
+[![File ExplorerExample](https://raw.githubusercontent.com/DioxusLabs/example-projects/master/file-explorer/image.png)](https://github.com/DioxusLabs/example-projects/tree/master/file-explorer)
 
 ### Mobile Support
 ---
@@ -82,7 +82,7 @@ Mobile is currently the least-supported renderer target for Dioxus. Mobile apps
 
 Mobile support is currently best suited for CRUD-style apps, ideally for internal teams who need to develop quickly but don't care much about animations or native widgets.
 
-[Jump to the getting started guide for Mobile.]()
+[Jump to the getting started guide for Mobile.](/reference/platforms/mobile)
 
 Examples:
 - [Todo App](https://github.com/DioxusLabs/example-projects/blob/master/ios_demo)

+ 24 - 21
docs/guide/src/ROADMAP.md

@@ -62,10 +62,12 @@ Generally, here's the status of each platform:
 
 
 ## Roadmap
+These Features are planned for the future of Dioxus:
+
 ---
 
 
-Core:
+### Core
 - [x] Release of Dioxus Core
 - [x] Upgrade documentation to include more theory and be more comprehensive
 - [ ] Support for HTML-side templates for lightning-fast dom manipulation
@@ -73,18 +75,18 @@ Core:
 - [ ] Support for ThreadSafe (Send + Sync)
 - [ ] Support for Portals
 
-SSR
+### SSR
 - [x] SSR Support + Hydration
 - [ ] Integrated suspense support for SSR
 
-Desktop
+### Desktop
 - [ ] Declarative window management
 - [ ] Templates for building/bundling
 - [ ] Fully native renderer
 - [ ] Access to Canvas/WebGL context natively
 
-Mobile
-- [ ] Mobile standard library 
+### Mobile
+- [ ] Mobile standard library
   - [ ] GPS
   - [ ] Camera
   - [ ] filesystem
@@ -93,22 +95,23 @@ Mobile
   - [ ] Bluetooth
   - [ ] Notifications
   - [ ] Clipboard
-  - [ ] 
-
-Bundling (CLI)
-- [x] translation from HTML into RSX
-- [ ] dev server
-- [ ] live reload
-- [ ] translation from JSX into RSX
-- [ ] hot module replacement
-- [ ] code splitting
-- [ ] asset macros
-- [ ] css pipeline
-- [ ] image pipeline
-
-Essential hooks
-- [ ] Router
-- [ ] Global state management
+- [ ] Animations
+- [ ] Native Renderer
+
+### Bundling (CLI)
+- [x] Translation from HTML into RSX
+- [x] Dev server
+- [x] Live reload
+- [x] Translation from JSX into RSX
+- [ ] Hot module replacement
+- [ ] Code splitting
+- [ ] Asset macros
+- [ ] Css pipeline
+- [ ] Image pipeline
+
+### Essential hooks
+- [x] Router
+- [x] Global state management
 - [ ] Resize observer
 
 

+ 20 - 8
docs/guide/src/SUMMARY.md

@@ -15,26 +15,38 @@
   - [Children and Attributes](components/component_children.md)
   - [How Data Flows](components/composing.md)
 - [Adding Interactivity](interactivity/index.md)
-  - [Hooks and Internal State](interactivity/hooks.md)
-  - [UseState and UseRef](interactivity/importanthooks.md) 
   - [Event Listeners](interactivity/event_handlers.md)
-  - [User Input and Controlled Components](interactivity/user_input.md)
-  - [Lifecycle, updates, and effects](interactivity/lifecycles.md)
+  - [Hooks](interactivity/hooks.md)
+  - [UseState](interactivity/usestate.md)
+  - [UseRef](interactivity/useref.md)
+  - [User Input](interactivity/user_input.md)
+  <!-- - [Effects](interactivity/lifecycles.md) -->
 - [Managing State](state/index.md)
   - [Local State](state/localstate.md)
-  - [Lifting State](state/liftingstate.md)
   - [Global State](state/sharedstate.md)
+  - [Lifting State](state/liftingstate.md)
   - [Error handling](state/errorhandling.md)
+- [Helper Crates](helpers/index.md)
+  - [Fermi](state/fermi.md)
+  - [Router](state/router.md)
 - [Working with Async](async/index.md)
-  - [Tasks](async/asynctasks.md)
-  - [Fetching](async/fetching.md)
+  - [UseFuture](async/use_future.md)
+  - [UseCoroutine](async/coroutines.md)
+  <!-- - [Fetching](async/fetching.md) -->
+  <!-- - [Updating State](async/loading_state.md)
+  - [WebSockets](async/sockets.md) -->
+  <!-- - [Tasks](async/asynctasks.md) -->
+
+<!--
 - [Putting it all together: Dog Search Engine](tutorial/index.md)
   - [New app](tutorial/new_app.md)
   - [Structuring our app](tutorial/structure.md)
   - [Defining State](tutorial/state.md)
   - [Defining Components](tutorial/components.md)
   - [Styling](tutorial/styling.md)
-  - [Bundling](tutorial/publishing.md)
+  - [Bundling](tutorial/publishing.md) -->
+
+
 - [Next Steps and Advanced Topics](final.md)
 
 

+ 183 - 0
docs/guide/src/async/coroutines.md

@@ -0,0 +1,183 @@
+# Coroutines
+
+Another good tool to keep in your async toolbox are coroutines. Coroutines are futures that can be manually stopped, started, paused, and resumed.
+
+Like regular futures, code in a Dioxus coroutine will run until the next `await` point before yielding. This low-level control over asynchronous tasks is quite powerful, allowing for infinitely looping tasks like WebSocket polling, background timers, and other periodic actions.
+
+## `use_coroutine`
+
+The basic setup for coroutines is the `use_coroutine` hook. Most coroutines we write will be polling loops using async/await.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let ws: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
+        // Connect to some sort of service
+        let mut conn = connect_to_ws_server().await;
+
+        // Wait for data on the service
+        while let Some(msg) = conn.next().await {
+            // handle messages
+        }
+    });
+}
+```
+
+For many services, a simple async loop will handle the majority of use cases.
+
+However, if we want to temporarily disable the coroutine, we can "pause" it using the `pause` method, and "resume" it using the `resume` method:
+
+```rust
+let sync: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
+    // code for syncing
+});
+
+if sync.is_running() {
+    cx.render(rsx!{
+        button {
+            onclick: move |_| sync.pause(),
+            "Disable syncing"
+        }
+    })
+} else {
+    cx.render(rsx!{
+        button {
+            onclick: move |_| sync.resume(),
+            "Enable syncing"
+        }
+    })
+}
+```
+
+This pattern is where coroutines are extremely useful - instead of writing all the complicated logic for pausing our async tasks like we would with JavaScript promises, the Rust model allows us to just not poll our future.
+
+## Sending Values
+
+You might've noticed the `use_coroutine` closure takes an argument called `rx`. What is that? Well, a common pattern in complex apps is to handle a bunch of async code at once. With libraries like Redux Toolkit, managing multiple promises at once can be challenging and a common source of bugs.
+
+With Coroutines, we have the opportunity to centralize our async logic. The `rx` parameter is an Unbounded Channel for code external to the coroutine to send data *into* the coroutine. Instead of looping on an external service, we can loop on the channel itself, processing messages from within our app without needing to spawn a new future. To send data into the coroutine, we would call "send" on the handle.
+
+
+```rust
+enum ProfileUpdate {
+    SetUsername(String),
+    SetAge(i32)
+}
+
+let profile = use_coroutine(&cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
+    let mut server = connect_to_server().await;
+
+    while let Ok(msg) = rx.next().await {
+        match msg {
+            ProfileUpdate::SetUsername(name) => server.update_username(name).await,
+            ProfileUpdate::SetAge(age) => server.update_age(age).await,
+        }
+    }
+});
+
+
+cx.render(rsx!{
+    button {
+        onclick: move |_| profile.send(ProfileUpdate::SetUsername("Bob".to_string())),
+        "Update username"
+    }
+})
+```
+
+For sufficiently complex apps, we could build a bunch of different useful "services" that loop on channels to update the app.
+
+```rust
+let profile = use_coroutine(&cx, profile_service);
+let editor = use_coroutine(&cx, editor_service);
+let sync = use_coroutine(&cx, sync_service);
+
+async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
+    // do stuff
+}
+
+async fn sync_service(rx: UnboundedReceiver<SyncCommand>) {
+    // do stuff
+}
+
+async fn editor_service(rx: UnboundedReceiver<EditorCommand>) {
+    // do stuff
+}
+```
+
+We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state *within* a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your *actual* state does not need to be tied up in a system like Fermi or Redux - the only Atoms that need to exist are those that are used to drive the display/UI.
+
+```rust
+static USERNAME: Atom<String> = |_| "default".to_string();
+
+fn app(cx: Scope) -> Element {
+    let atoms = use_atom_root(&cx);
+
+    use_coroutine(&cx, |rx| sync_service(rx, atoms.clone()));
+
+    cx.render(rsx!{
+        Banner {}
+    })
+}
+
+fn Banner(cx: Scope) -> Element {
+    let username = use_read(&cx, USERNAME);
+
+    cx.render(rsx!{
+        h1 { "Welcome back, {username}" }
+    })
+}
+```
+
+Now, in our sync service, we can structure our state however we want. We only need to update the view values when ready.
+
+```rust
+enum SyncAction {
+    SetUsername(String),
+}
+
+async fn sync_service(mut rx: UnboundedReceiver<SyncAction>, atoms: AtomRoot) {
+    let username = atoms.write(USERNAME);
+    let errors = atoms.write(ERRORS);
+
+    while let Ok(msg) = rx.next().await {
+        match msg {
+            SyncAction::SetUsername(name) => {
+                if set_name_on_server(&name).await.is_ok() {
+                    username.set(name);
+                } else {
+                    errors.make_mut().push("SetUsernameFailed");
+                }
+            }
+        }
+    }
+}
+```
+
+## Yielding Values
+
+To yield values from a coroutine, simply bring in a `UseState` handle and set the value whenever your coroutine completes its work.
+
+
+```rust
+let sync_status = use_state(&cx, || Status::Launching);
+let sync_task = use_coroutine(&cx, |rx: UnboundedReceiver<SyncAction>| {
+    to_owned![sync_status];
+    async move {
+        loop {
+            delay_ms(1000).await;
+            sync_status.set(Status::Working);
+        }
+    }
+})
+```
+
+## Automatic injection into the Context API
+
+Coroutine handles are automatically injected through the context API. `use_coroutine_handle` with the message type as a generic can be used to fetch a handle.
+
+```rust
+fn Child(cx: Scope) -> Element {
+    let sync_task = use_coroutine_handle::<SyncAction>(&cx);
+
+    sync_task.send(SyncAction::SetUsername);
+}
+```

+ 0 - 2
docs/guide/src/async/fetching.md

@@ -1,4 +1,2 @@
 # Fetching
 
-
-This section is currently under construction! 🏗

+ 88 - 6
docs/guide/src/async/index.md

@@ -4,19 +4,101 @@ Not all apps you'll build can be self-contained with synchronous code. You'll of
 
 So far, we've only talked about building apps with synchronous code, so this chapter will focus integrating asynchronous code into your app.
 
-
 ## The Runtime
 
-By default, Dioxus-Desktop ships with the `Tokio` runtime and automatically sets everything up for you.
+By default, Dioxus-Desktop ships with the `Tokio` runtime and automatically sets everything up for you. This is currently not configurable, though it would be easy to write an integration for Dioxus desktop that uses a different asynchronous runtime.
+
+## Send/Sync
+Writing apps that deal with Send/Sync can be frustrating at times. Under the hood, Dioxus is not currently thread-safe, so any async code you write does *not* need to be `Send/Sync`. That means that you can use non-thread-safe structures like `Cell`, `Rc`, and `RefCell`.
 
+All async code in your app is polled on a `LocalSet`, so you can also use `tokio::spawn_local`.
 
+## Spawning a future
 
-## Send/Sync
-Writing apps that deal with Send/Sync can be frustrating at times. Under the hood, Dioxus is not currently thread-safe, so any async code you write does *not* need to be `Send/Sync`. That means Cell/Rc/RefCell are all fair game.
+Currently, all futures in Dioxus must be `'static`. To spawn a future, simply call `cx.spawn()`.
+
+```rust
+rsx!{
+    button {
+        onclick: move |_| cx.spawn(async move {
+            let result = fetch_thing().await;
+        })
+    }
+}
+```
+
+Calling `spawn` will give you a `JoinHandle` which lets you cancel or pause the future.
+
+
+## Setting state from within a future
+
+If you start to write some async code, you'll quickly be greeted with the infamous error about borrowed items in static closures.
+
+```
+error[E0759]: `cx` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+  --> examples/tasks.rs:13:27
+   |
+12 | fn app(cx: Scope) -> Element {
+   |            ----- this data with an anonymous lifetime `'_`...
+13 |     let count = use_state(&cx, || 0);
+   |                           ^^^ ...is used here...
+14 |
+15 |     use_future(&cx, (), move |_| {
+   |     ---------- ...and is required to live as long as `'static` here
+   |
+note: `'static` lifetime requirement introduced by this bound
+  --> /Users/jonkelley/Development/dioxus/packages/hooks/src/usefuture.rs:25:29
+   |
+25 |     F: Future<Output = T> + 'static,
+   |                             ^^^^^^^
+
+For more information about this error, try `rustc --explain E0759`.
+error: could not compile `dioxus` due to previous error
+```
+
+Rustc tends to provide great feedback in its errors, but this particular error is actually quite unhelpful. For reference, here's our code:
+
+```rust
+fn app(cx: Scope) -> Element {
+    let count = use_state(&cx, || 0);
+
+    cx.spawn(async move {
+        tokio::time::sleep(Duration::from_millis(1000)).await;
+        count += 1;
+    });
+
+    cx.render(rsx! {
+        button {
+            onclick: move |_| count.set(0),
+            "Reset the count"
+        }
+    })
+}
+```
+
+Simple, right? We spawn a future that updates the value after one second has passed. Well, yes, and no. Our `count` value is only valid for the lifetime of this component, but our future could still be running even after the component re-renders. By default, Dioxus places a requirement on all futures to be `'static`, meaning they can't just borrow state from our hooks outright.
 
+To get around this, we need to get a `'static` handle to our state. All Dioxus hooks implement `Clone`, so you simply need to call clone before spawning your future. Any time you get the particular error above, make sure you call `Clone` or `ToOwned`.
 
+```rust
+cx.spawn({
+    let mut count = count.clone();
+    async move {
+        tokio::time::sleep(Duration::from_millis(1000)).await;
+        count += 1;
+    }
+});
+```
 
-All async code in your app is polled on a `LocalSet`, so any async code we w
+To make this a little bit easier, Dioxus exports the `to_owned!` macro which will create a binding as shown above, which can be quite helpful when dealing with many values.
 
+```rust
+cx.spawn({
+    to_owned![count, age, name, description, etc];
+    async move {
+        tokio::time::sleep(Duration::from_millis(1000)).await;
+        count += 1;
+    }
+});
+```
 
-> This section is currently under construction! 🏗

+ 8 - 0
docs/guide/src/async/loading_state.md

@@ -0,0 +1,8 @@
+# Updating State
+
+After your future has been spawned, you might want to update the state of our UI. Possible implementations might include:
+
+- A loading state
+- A transition state
+- Showing failures
+- Listening to sockets and updating the app

+ 1 - 0
docs/guide/src/async/sockets.md

@@ -0,0 +1 @@
+# WebSockets

+ 85 - 0
docs/guide/src/async/use_future.md

@@ -0,0 +1,85 @@
+# UseFuture
+
+When dealing with asynchronous code, you might need to wait for some action to complete before rendering your component. If you had to build this abstraction yourself, you'd probably end up with some `use_state` spaghetti code.
+
+One of the core hooks that Dioxus provides is `use_future` - a simple hook that lets you tap into a running task.
+
+## Use case
+
+The simplest use case of `use_future` is to prevent rendering until some asynchronous code has been completed. Dioxus doesn't currently have a library as sophisticated as React Query for prefetching tasks, but we can get some of the way there with `use_future`. In one of the Dioxus examples, we use `use_future` to download some search data before rendering the rest of the app:
+
+```rust
+fn app(cx: Scope) -> Element {
+    // set "breeds" to the current value of the future
+    let breeds = use_future(&cx, (), |_| async move {
+        reqwest::get("https://dog.ceo/api/breeds/list/all")
+            .await
+            .unwrap()
+            .json::<ListBreeds>()
+            .await
+    });
+
+    let status = match breeds.value() {
+        Some(Ok(val)) => "ready!",
+        Some(Err(err)) => "errored!",
+        None => "loading!",
+    }
+}
+```
+
+On first run, the code inside `use_future` will be submitted to the Dioxus scheduler once the component has rendered. Since there's no data ready when the component loads the first time, its "value" will be `None`.
+
+However, once the future is finished, the component will be re-rendered and a new screen will be displayed - Ok or Err, depending on the outcome of our fetch.
+
+
+
+## Restarting the Future
+
+The example we showed above will only ever run once. What happens if some value changed on the server and we need to update our future's value?
+
+Well, the UseFuture handle provides a handy "restart" method. We can wire this up to a button or some other comparison code to get a regenerating future.
+
+```rust
+fn app(cx: Scope) -> Element {
+    // set "breeds" to the current value of the future
+    let dog = use_future(&cx, (), |_| async move {
+        reqwest::get("https://dog.ceo/api/breeds/image/random")
+            .await
+            .unwrap()
+            .json::<RandomDog>()
+            .await
+    });
+
+    cx.render(match breeds.value() {
+        Some(Ok(val)) => rsx!(div {
+            img { src: "{val.message}"}
+            button {
+                onclick: move |_| dog.restart(),
+                "Click to fetch a new dog"
+            }
+        }),
+        Some(Err(err)) => rsx!("Failed to load dog"),
+        None => rsx!("Loading dog image!"),
+    })
+}
+```
+
+## With Dependencies
+
+We showed that UseFuture can be regenerated manually, but how can we automatically get it to update whenever some input value changes? This is where the "dependencies" tuple comes into play. We just need to add a value into our tuple argument and it'll be automatically cloned into our future when it starts.
+
+
+```rust
+#[inline_props]
+fn RandomDog(cx: Scope, breed: String) -> Element {
+    let dog = use_future(&cx, (breed,), |(breed)| async move {
+        reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
+            .await
+            .unwrap()
+            .json::<RandomDog>()
+            .await
+    });
+
+    // some code as before
+}
+```

+ 9 - 8
docs/guide/src/components/component_children.md

@@ -1,6 +1,6 @@
 # Passing children and attributes
 
-Often times, you'll want to wrap some important functionality *around* your state, not directly nested *inside* another component. In these cases, you'll want to pass elements and attributes into a component and let the component place them appropriately.
+Oftentimes, you'll want to wrap some important functionality *around* your state, not directly nested *inside* another component. In these cases, you'll want to pass elements and attributes into a component and let the component place them appropriately.
 
 In this chapter, you'll learn about:
 - Passing elements into components
@@ -30,7 +30,7 @@ struct ClickableProps<'a> {
     title: &'a str
 }
 
-fn Clickable(cx: Scope<ClickableProps>) -> Element {
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
     cx.render(rsx!(
         a {
             href: "{cx.props.href}"
@@ -64,7 +64,7 @@ struct ClickableProps<'a> {
     body: Element<'a>
 }
 
-fn Clickable(cx: Scope<ClickableProps>) -> Element {
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
     cx.render(rsx!(
         a {
             href: "{cx.props.href}",
@@ -98,7 +98,7 @@ struct ClickableProps<'a> {
     children: Element<'a>
 }
 
-fn Clickable(cx: Scope<ClickableProps>) -> Element {
+fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
     cx.render(rsx!(
         a {
             href: "{cx.props.href}",
@@ -125,7 +125,7 @@ While technically allowed, it's an antipattern to pass children more than once i
 However, because the `Element` is transparently a `VNode`, we can actually match on it to extract the nodes themselves, in case we are expecting a specific format:
 
 ```rust
-fn clickable(cx: Scope<ClickableProps>) -> Element {
+fn clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
     match cx.props.children {
         Some(VNode::Text(text)) => {
             // ...
@@ -137,6 +137,8 @@ fn clickable(cx: Scope<ClickableProps>) -> Element {
 }
 ```
 
+Passing nodes through props means that they are immutable. If you find yourself needing to mutate nodes passed through props, consider creating a new node in its place that takes on its attributes, children, and listeners.
+
 <!-- ## Passing attributes
 
 In the cases where you need to pass arbitrary element properties into a component - say to add more functionality to the `<a>` tag, Dioxus will accept any quoted fields. This is similar to adding arbitrary fields to regular elements using quotes.
@@ -160,7 +162,7 @@ struct ClickableProps<'a> {
     attributes: Attributes<'a>
 }
 
-fn clickable(cx: Scope<ClickableProps>) -> Element {
+fn clickable(cx: Scope<ClickableProps<'a>>) -> Element {
     cx.render(rsx!(
         a {
             ..cx.props.attributes,
@@ -184,7 +186,7 @@ struct ClickableProps<'a> {
     onclick: EventHandler<'a, MouseEvent>
 }
 
-fn clickable(cx: Scope<ClickableProps>) -> Element {
+fn clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
     cx.render(rsx!(
         a {
             onclick: move |evt| cx.props.onclick.call(evt)
@@ -214,4 +216,3 @@ In this chapter, we learned:
 - How the `attributes` field works on component properties
 - How to convert `listeners` into `EventHandlers` for components
 - How to extend any node with custom attributes and children
-

+ 13 - 13
docs/guide/src/components/composing.md

@@ -1,6 +1,6 @@
-# Thinking in React
+# Thinking in Reactively
 
-We've finally reached the point in our tutorial where we can talk about the theory of Reactive interfaces. We've talked about defining a declarative view, but not about the aspects that make our code *reactive*.
+We've finally reached the point in our tutorial where we can talk about the theory of Reactivity. We've talked about defining a declarative view, but not about the aspects that make our code *reactive*.
 
 Understanding the theory of reactive programming is essential to making sense of Dioxus and writing effective, performant UIs.
 
@@ -15,7 +15,7 @@ This section is a bit long, but worth the read. We recommend coffee, tea, and/or
 
 ## Reactive Programming
 
-Dioxus is one the very few Rust libraries that provide a "Reactive Programming Model". The term "Reactive programming" is a classification of programming paradigm - much like functional or imperative programming. This is a very important distinction since it affects how we *think* about our code.
+Dioxus is one of a handful of Rust libraries that provide a "Reactive Programming Model". The term "Reactive programming" is a classification of programming paradigm - much like functional or imperative programming. This is a very important distinction since it affects how we *think* about our code.
 
 Reactive programming is a programming model concerned with deriving computations from asynchronous data flow. Most reactive programs are comprised of datasources, intermediate computations, and a final result.
 
@@ -51,7 +51,7 @@ fn compute_graph(constant: i32, seconds: i32) -> bool {
 
 ## How is Dioxus Reactive?
 
-The Dioxus VirtualDom provides us a framework for reactive programming. When we build apps with dioxus, we need to provide our own datasources. This can be either initial props or some values fetched from the network. We then pass this data through our app into components through properties. 
+The Dioxus VirtualDom provides us a framework for reactive programming. When we build apps with dioxus, we need to provide our own datasources. This can be either initial props or some values fetched from the network. We then pass this data through our app into components through properties.
 
 If we represented the reactive graph presented above in Dioxus, it would look very similar:
 
@@ -61,8 +61,8 @@ fn RenderGraph(cx: Scope) -> Element {
     let seconds = use_datasource(SECONDS);
     let constant = use_state(&cx, || 1);
 
-    cx.render(rsx!( 
-        RenderG { seconds: seconds } 
+    cx.render(rsx!(
+        RenderG { seconds: seconds }
         RenderT { seconds: seconds, constant: constant }
     ))
 }
@@ -108,8 +108,8 @@ For local state in hooks, Dioxus gives us the `use_hook` method which returns an
 fn app(cx: Scope) -> Element {
     let mut count = cx.use_hook(|_| 0);
     cx.render(rsx!{
-        button { 
-            onclick: move |_| *count += 1, 
+        button {
+            onclick: move |_| *count += 1,
             "Count: {count}"
         }
     })
@@ -119,11 +119,11 @@ fn app(cx: Scope) -> Element {
 However, when this value is written to, the component does not know to be reevaluated. We must explicitly tell Dioxus that this component is "dirty" and needs to be re-rendered. This is done through the `cx.needs_update` method:
 
 ```rust
-button { 
+button {
     onclick: move |_| {
         *count += 1;
         cx.needs_update();
-    }, 
+    },
     "Count: {count}"
 }
 ```
@@ -144,7 +144,7 @@ With the `provide_context` and `consume_context` methods on `Scope`, we can shar
 
 To make app-global state easier to reason about, Dioxus makes all values provided through `provide_context` immutable. This means any library built on top of `provide_context` needs to use interior mutability to modify shared global state.
 
-In these cases, App-Global state needs to manually track which components need to be re-generated. 
+In these cases, App-Global state needs to manually track which components need to be re-generated.
 
 To regenerate *any* component in your app, you can get a handle to the Dioxus' internal scheduler through `schedule_update_any`:
 
@@ -165,7 +165,7 @@ The tree of UI that dioxus creates will roughly look like the tree of components
 
 ![Tree of UI](../images/component_tree.png)
 
-But what happens when we call `needs_update` after modifying some important state? Well, if Dioxus called our component's function again, then we would produce new, different nodes. In fact, this is exactly what Dioxus does! 
+But what happens when we call `needs_update` after modifying some important state? Well, if Dioxus called our component's function again, then we would produce new, different nodes. In fact, this is exactly what Dioxus does!
 
 At this point, we have some old nodes and some new nodes. Again, we call this "rendering" because Dioxus had to create new nodes because of our explicit actions. Any time new nodes get created, our VirtualDom is being "rendered."
 
@@ -216,7 +216,7 @@ However, for components that borrow data, it doesn't make sense to implement Par
 You can technically override this behavior by implementing the `Props` trait manually, though it's unsafe and easy to mess up:
 
 ```rust
-impl Properties for CustomProps {
+unsafe impl Properties for CustomProps {
     fn memoize(&self, other &Self) -> bool {
         self != other
     }

+ 43 - 11
docs/guide/src/components/propsmacro.md

@@ -1,12 +1,14 @@
 # Component Properties
+
 Dioxus components are functions that accept Props as input and output an Element. In fact, the `App` function you saw in the previous chapter was a component with no Props! Most components, however, will need to take some Props to render something useful – so, in this section, we'll learn about props:
 
 - Deriving the Props trait
 - Memoization through PartialEq
 - Optional fields on props
-- The inline_props macro    
+- The inline_props macro
 
 ## Props
+
 The input of your Component must be passed in a single struct, which must implement the `Props` trait. We can derive this trait automatically with `#[derive(Props)]`.
 
 > Dioxus `Props` is very similar to [@idanarye](https://github.com/idanarye)'s [TypedBuilder crate](https://github.com/idanarye/rust-typed-builder) and supports many of the same parameters.
@@ -56,10 +58,10 @@ And we can see that the Component indeed gets rendered:
 ![Screenshot of running app. Text: "+ \ 42 \ -"](component_example_votes.png)
 
 > The simplest Owned Props you can have is `()` - or no value at all. This is what the `App` Component takes as props. `Scope` accepts a generic for the Props which defaults to `()`.
-> 
+>
 > ```rust
 >// this scope
->Scope<()> 
+>Scope<()>
 >
 >// is the same as this scope
 >Scope
@@ -131,23 +133,29 @@ Borrowed Props cannot be safely memoized. However, this is not a problem – Dio
 
 ## Optional Props
 
-You can easily create optional fields by attaching the `optional` modifier to a field:
+You can easily create optional fields by using the `Option<…>` type for a field:
 
 ```rust
 #[derive(Props, PartialEq)]
 struct MyProps {
     name: String,
 
-    #[props(optional)]
     description: Option<String>
 }
 
 fn Demo(cx: MyProps) -> Element {
-    todo!()
+    let text = match cx.props.description {
+        Some(d) => d,             // if a value is provided
+        None => "No description"  // if the prop is omitted
+    };
+
+    cx.render(rsx! {
+        "{name}": "{text}"
+    })
 }
 ```
-
-Then, we can completely omit the description field when calling the component:
+In this example `name` is a required prop and `description` is optional.
+This means we can completely omit the description field when calling the component:
 
 ```rust
 rsx!{
@@ -157,15 +165,39 @@ rsx!{
     }
 }
 ```
+Additionally if we provide a value we don't have to wrap it with `Some(…)`. This is done automatically for us:
+
+```rust
+rsx!{
+    Demo {
+        name: "Thing".to_string(),
+        description: "This is explains it".to_string(),
+    }
+}
+```
+
+If you want to make a prop required even though it is of type `Option` you can provide the `!optional` modifier:
+
+```rust
+#[derive(Props, PartialEq)]
+struct MyProps {
+    name: String,
+
+    #[props(!optional)]
+    description: Option<String>
+}
+```
+
+This can be especially useful if you have a type alias named `Option` in the current scope.
+
+For more information on how tags work, check out the [TypedBuilder](https://github.com/idanarye/rust-typed-builder) crate. However, all attributes for props in Dioxus are flattened (no need for `setter` syntax) and the `optional` field is new. The `optional` modifier is a combination of two separate modifiers: `default` and `strip_option` and it is automatically detected on `Option<…>` types.
 
-The `optional` modifier is a combination of two separate modifiers: `default` and `strip_option`. The full list of modifiers includes:
+The full list of Dioxus' modifiers includes:
 
 - `default` - automatically add the field using its `Default` implementation
-- `strip_option` - automatically wrap values at the call site in `Some`
 - `optional` - alias for `default` and `strip_option`
 - `into` - automatically call `into` on the value at the callsite
 
-For more information on how tags work, check out the [TypedBuilder](https://github.com/idanarye/rust-typed-builder) crate. However, all attributes for props in Dioxus are flattened (no need for `setter` syntax) and the `optional` field is new.
 
 ## The `inline_props` macro
 

+ 1 - 1
docs/guide/src/elements/conditional_rendering.md

@@ -1,6 +1,6 @@
 # Conditional Rendering
 
-Your components will often need to display different things depending on different conditions. With Dioxus, we can use Rust's normal control flow to conditional hide, show, and modify the structure of our markup.
+Your components will often need to display different things depending on different conditions. With Dioxus, we can use Rust's normal control flow to conditionally hide, show, and modify the structure of our markup.
 
 In this chapter, you'll learn:
 - How to return different Elements depending on a condition

+ 7 - 8
docs/guide/src/elements/special_attributes.md

@@ -7,7 +7,6 @@ In this section, we'll cover special attributes built into Dioxus:
 - `dangerous_inner_html`
 - Boolean attributes
 - `prevent_default`
-<!-- - `..Attributes` -->
 - event handlers as string attributes
 - `value`, `checked`, and `selected`
 
@@ -31,7 +30,7 @@ fn BlogPost(cx: Scope) -> Element {
 ```
 
 > Note! This attribute is called "dangerous_inner_html" because it is **dangerous** to pass it data you don't trust. If you're not careful, you can easily expose cross-site-scripting (XSS) attacks to your users.
-> 
+>
 > If you're handling untrusted input, make sure to sanitize your HTML before passing it into `dangerous_inner_html` – or just pass it to a Text Element to escape any HTML tags.
 
 
@@ -49,9 +48,9 @@ rsx!{
     }
 }
 ```
-wouldn't actually render the `hidden` attribute: 
+wouldn't actually render the `hidden` attribute:
 ```html
-<div>hello</div> 
+<div>hello</div>
 ```
 
 Not all attributes work like this however. *Only the following attributes* have this behavior:
@@ -87,9 +86,9 @@ For any other attributes, a value of `"false"` will be sent directly to the DOM.
 
 ## Stopping form input and navigation with `prevent_default`
 
-Currently, calling `prevent_default` on events in EventHandlers is not possible from Desktop/Mobile. Until this is supported, it's possible to prevent default using the `prevent_default` attribute. 
+Currently, calling `prevent_default` on events in EventHandlers is not possible from Desktop/Mobile. Until this is supported, it's possible to prevent default using the `prevent_default` attribute.
 
-> Note: you cannot conditionally prevent default with this approach. This is a limitation until synchronous event handling is available across the Webview boundary 
+> Note: you cannot conditionally prevent default with this approach. This is a limitation until synchronous event handling is available across the Webview boundary
 
 To use `prevent_default`, simply attach the `prevent_default` attribute to a given element and set it to the name of the event handler you want to prevent default on. We can attach this attribute multiple times for multiple attributes.
 
@@ -104,7 +103,7 @@ rsx!{
     }
 }
 ```
-<!-- 
+<!--
 ## Passing attributes into children: `..Attributes`
 
 > Note: this is an experimental, unstable feature not available in released versions of Dioxus. Feel free to skip this section.
@@ -188,5 +187,5 @@ In this chapter, we learned:
 <!-- todo
 There's more to elements! For further reading, check out:
 
-- [Custom Elements]() 
+- [Custom Elements]()
 -->

+ 4 - 2
docs/guide/src/elements/vnodes.md

@@ -8,6 +8,7 @@ In this chapter, we'll cover:
 - Element properties
 
 ## Declaring our first Element
+
 Because Dioxus is mostly used with HTML/CSS renderers, the default Element "collection" is HTML. Provided the `html` feature is not disabled, we can declare Elements using the `rsx!` macro:
 
 ```rust
@@ -29,6 +30,7 @@ Produces:
 ```
 
 We can construct any valid HTML tag with the `tag {}` pattern and expect the resulting HTML structure to resemble our declaration.
+
 ## Composing Elements
 
 Of course, we need more complex structures to make our apps actually useful! Just like HTML, the `rsx!` macro lets us nest Elements inside of each other.
@@ -81,7 +83,7 @@ let name = "Bob";
 rsx! ( "hello {name}" )
 ```
 
-Unfortunately, you cannot drop in arbitrary expressions directly into the string literal. In the cases where we need to compute a complex value, we'll want to use `format_args!` directly. Due to specifics of the `rsx!` macro (which we'll cover later), our call to `format_args` must be contained within square braces.
+Unfortunately, you cannot yet drop in arbitrary expressions directly into the string literal with Rust. In the cases where we need to compute a complex value, we'll want to use `format_args!` directly. Due to specifics of the `rsx!` macro (which we'll cover later), our call to `format_args` must be contained within square braces.
 
 ```rust
 rsx!( [format_args!("Hello {}", if enabled { "Jack" } else { "Bob" } )] )
@@ -150,7 +152,7 @@ All element attributes must occur *before* child elements. The `rsx!` macro will
 
 Listeners are a special type of Attribute that only accept functions. Listeners let us attach functionality to our Elements by running a provided closure whenever the specified Listener is triggered.
 
-We'll cover listeners in more depth in the Listeners chapter, but for now, just know that every listener must start with the `on` keyword and accepts closures.
+We'll cover listeners in more depth in the Adding Interactivity chapter, but for now, just know that every listener starts with "on" and accepts closures.
 
 ```rust
 rsx!(

+ 14 - 9
docs/guide/src/hello_world.md

@@ -63,7 +63,7 @@ $ cat Cargo.toml
 [package]
 name = "hello-dioxus"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
@@ -81,6 +81,13 @@ $ cargo add dioxus --features desktop
 
 It's very important to add `dioxus` with the `desktop` feature for this example. The `dioxus` crate is a batteries-include crate that combines a bunch of utility crates together, ensuring compatibility of the most important parts of the ecosystem. Under the hood, the `dioxus` crate configures various renderers, hooks, debug tooling, and more. The `desktop` feature ensures the we only depend on the smallest set of required crates to compile and render.
 
+If you system does not provide the `libappindicator3` library, like Debian/bullseye, you can enable the replacement `ayatana` with an additional flag:
+
+```shell
+$ # On Debian/bullseye use:
+$ cargo add dioxus --features desktop --features ayatana
+```
+
 If you plan to develop extensions for the `Dioxus` ecosystem, please use the `dioxus` crate with the `core` feature to limit the amount of dependencies your project brings in.
 
 ### Our first app
@@ -92,10 +99,10 @@ use dioxus::prelude::*;
 
 
 fn main() {
-    dioxus::desktop::launch(App);
+    dioxus::desktop::launch(app);
 }
 
-fn App(cx: Scope) -> Element {
+fn app(cx: Scope) -> Element {
     cx.render(rsx! (
         div { "Hello, world!" }
     ))
@@ -108,24 +115,24 @@ At this point, you could call `cargo run` and be greeted with a simple `Hello, W
 
 ### Dissecting our example
 
-The `use` statement at the top of our app imports everything from the the `prelude` module. `use`-ing the prelude imports the right traits, types, and macros needed for working with Dioxus.
+The `use` statement at the top of our app imports everything from the `prelude` module. `use`-ing the prelude imports the right traits, types, and macros needed for working with Dioxus.
 
 ```rust
 use dioxus::prelude::*;
 ```
 
-This initialization code launches a Tokio runtime on a helper thread where your code will run. Then, the WebView renderer will be launched on the main-thread. Due to platform requirements, the main thread is blocked by your app's event loop.
+This initialization code launches a Tokio runtime on a helper thread where your code will run. Then, the WebView renderer will be launched on the main thread. Due to platform requirements, the main thread is blocked by your app's event loop.
 
 ```rust
 fn main() {
-    dioxus::desktop::launch(App);
+    dioxus::desktop::launch(app);
 }
 ```
 
 Finally, our app. Every component in Dioxus is a function that takes in `Context` and `Props` and returns an `Element`.
 
 ```rust
-fn App(cx: Scope) -> Element {
+fn app(cx: Scope) -> Element {
     cx.render(rsx! {
         div { "Hello, world!" }
     })
@@ -143,5 +150,3 @@ For now, just know that `Scope` lets you store state with hooks and render eleme
 ## Moving on
 
 Congrats! You've built your first desktop application with Dioxus. Next, we're going to learn about the basics of building interactive user interfaces.
-
-

+ 47 - 0
docs/guide/src/helpers/index.md

@@ -0,0 +1,47 @@
+# Helper Crates
+
+Because the Dioxus ecosystem is fairly young, there aren't a ton of third-party libraries designed to "get things done." That's where the Dioxus helper crates come in. These are officially supported crates built on top of existing libraries to solve some of the common barriers to building apps.
+
+## Router
+
+Quickly add a cross-platform router to structure your app.
+
+[Link](https://github.com/DioxusLabs/dioxus/tree/master/packages/router)
+
+## Fermi
+
+Global state as easy as `use_state`.
+
+[Link](https://github.com/DioxusLabs/dioxus/tree/master/packages/fermi)
+
+## Query
+
+This crate has yet to be developed! However, we do plan on providing a crate for good fetching and query support.
+
+## 3rd-party - Toast
+
+Toast notifications, curtesy of [@mrxiaozhuox](https://github.com/mrxiaozhuox).
+
+[Link](https://github.com/mrxiaozhuox/dioxus-toast)
+
+## 3rd-party - HeroIcon
+
+Collection of helpful hero icons, curtesy of [@autarch](https://github.com/autarch).
+
+
+[Link](https://github.com/houseabsolute/dioxus-heroicons)
+
+## 3rd-party - Katex
+
+Draw beautiful equations, curtesy of [@oovm](https://github.com/oovm)
+
+[Link](https://github.com/oovm/katex-wasm/tree/dev/projects/dioxus-katex)
+
+
+## 3rd-party - PrimsJS
+
+Highlight your code blocks with ease, curtesy of [@oovm](https://github.com/oovm)
+
+[Link](https://github.com/oovm/katex-wasm/tree/dev/projects/dioxus-katex)
+
+

+ 116 - 1
docs/guide/src/interactivity/event_handlers.md

@@ -1,3 +1,118 @@
 # Event handlers
 
-> This section is currently under construction! 🏗
+To make our boring UIs less static and more interesting, we want to add the ability to interact with user input. To do this, we need to add some event handlers.
+
+
+## The most basic events: clicks
+
+If you've poked around in the Dioxus examples at all, you've definitely noticed the support for buttons and clicks. To add some basic action when a button is clicked, we need to define a button and then attach an "onclick" handler to it.
+
+```rust
+fn app(cx: Scope) -> Element {
+    cx.render(rsx!{
+        button {
+            onclick: move |evt| println!("I've been clicked!"),
+            "click me!"
+        }
+    })
+}
+```
+
+If you're using the builder pattern, it's pretty simple too. `onclick` is a method for any builder with HTML elements.
+
+```rust
+fn app(cx: Scope) -> Element {
+    button(&cx)
+        .onclick(move |evt| println!("I've been clicked!"))
+        .text("click me!")
+        .build()
+}
+```
+
+The event handler is different in Dioxus than other libraries. Event handlers in Dioxus may borrow any data that has a lifetime that matches the component's scope. This means we can save a value with `use_hook` and then use it in our handler.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let val = cx.use_hook(|_| 10);
+
+    button(&cx)
+        .onclick(move |evt| println!("Current number {val}"))
+        .text("click me!")
+        .build()
+}
+```
+
+
+## The `Event` object
+
+When the listener is fired, Dioxus will pass in any related data through the `event` parameter. This holds helpful state relevant to the event. For instance, on forms, Dioxus will fill in the "values" field.
+
+```rust
+// the FormEvent is roughly
+struct FormEvent {
+    value: String,
+    values: HashMap<String, String>
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx!{
+        form {
+            onsubmit: move |evt| {
+                println!("Values of form are {evt.values:#?}");
+            }
+            input { id: "password", name: "password" }
+            input { id: "username", name: "username" }
+        }
+    })
+}
+```
+
+## Stopping propagation
+
+With a complex enough UI, you might realize that listeners can actually be nested.
+
+```rust
+div {
+    onclick: move |evt| {},
+    "outer",
+    div {
+        onclick: move |evt| {},
+        "inner"
+    }
+}
+```
+
+In this particular layout, a click on the inner div is transitively also a click on the outer div. If we didn't want the outer div to be triggered every time we trigger the inner div, then we'd want to call `cancel_bubble()`.
+
+This will prevent any listeners above the current listener from being triggered.
+
+```rust
+div {
+    onclick: move |evt| {},
+    "outer",
+    div {
+        onclick: move |evt| {
+            // now, outer won't be triggered
+            evt.cancel_bubble();
+        },
+        "inner"
+    }
+}
+```
+
+## Prevent Default
+
+With HTML-based renderers, the browser will automatically perform some action. For text inputs, this would be entering the provided key. For forms, this might involve navigating the page.
+
+In some instances, you don't want this default behavior. In these cases, instead of handling the event directly, you'd want to prevent any default handlers.
+
+Normally, in React or JavaScript, you'd call "preventDefault" on the event in the callback. Dioxus does *not* currently support this behavior. Instead, you need to add an attribute to the element generating the event.
+
+```rust
+form {
+    prevent_default: "onclick",
+    onclick: move |_|{
+        // handle the event without navigating the page.
+    }
+}
+```

+ 1 - 2
docs/guide/src/interactivity/hooks.md

@@ -139,8 +139,7 @@ fn Child(cx: Scope, name: String) -> Element {
 }
 
 // ✅ Or, use a hashmap with use_ref
-```rust
-let ages = use_ref(&cx, |_| HashMap::new());
+let ages = use_ref(&cx, || HashMap::new());
 
 names.iter().map(|name| {
     let age = ages.get(name).unwrap();

+ 0 - 117
docs/guide/src/interactivity/importanthooks.md

@@ -8,120 +8,3 @@ Most components you will write in Dioxus will need to store state somehow. For l
 Both of these hooks are extremely powerful and flexible, so we've dedicated this section to understanding them properly.
 
 > These two hooks are not the only way to store state. You can always build your own hooks!
-
-## `use_state`
-
-The `use_state` hook is very similar to its React counterpart. When we use it, we get two values: 
-
-- The value itself as an `&T`
-- A handle to set the value `&UseState<T>`
-
-```rust
-let (count, set_count) = use_state(&cx, || 0);
-
-// then to set the count
-set_count(count + 1)
-```
-
-However, the `set_count` object is more powerful than it looks. You can use it as a closure, but you can also call methods on it to do more powerful operations.
-
-For instance, we can get a handle to the current value at any time:
-
-```rust
-let current: Rc<T> = set_count.current();
-```
-
-Or, we can get the inner handle to set the value
-
-```rust
-let setter: Rc<dyn Fn(T)> = set_count.setter();
-```
-
-Or, we can set a new value using the current value as a reference:
-
-```rust
-set_count.modify(|i| i + 1);
-```
-
-If the value is cheaply cloneable, then we can call `with_mut` to get a mutable reference to the value:
-
-```rust
-set_count.with_mut(|i| *i += 1);
-```
-
-Alternatively, we can call `make_mut` which gives us a `RefMut` to the underlying value:
-
-```rust
-*set_count.make_mut() += 1;
-```
-
-Plus, the `set_count` handle is cloneable into async contexts, so we can use it in futures.
-
-```rust
-// count up infinitely
-cx.spawn({
-    to_owned![set_count]; 
-    async move {
-        loop {
-            wait_ms(100).await;
-            set_count.modify(|i| i + 1);
-        }
-    }
-})
-```
-
-## `use_ref`
-
-You might've noticed a fundamental limitation to `use_state`: to modify the value in-place, it must be cheaply cloneable. But what if your type is not cheap to clone?
-
-In these cases, you should reach for `use_ref` which is essentially just a glorified `Rc<RefCell<T>>` (Rust [smart pointers](https://doc.rust-lang.org/book/ch15-04-rc.html)).
-
-This provides us some runtime locks around our data, trading reliability for performance. For most cases though, you will find it hard to make `use_ref` crash.
-
-> Note: this is *not* exactly like its React counterpart since calling `write` will cause a re-render. For more React parity, use the `write_silent` method.
-
-To use the hook:
-
-```rust
-let names = use_ref(&cx, || vec!["susie", "calvin"]);
-```
-
-To read the hook values, use the `read()` method:
-
-```rust
-cx.render(rsx!{
-    ul {
-        names.read().iter().map(|name| {
-            rsx!{ "{name}" }
-        })
-    }
-})
-```
-
-And then to write into the hook value, use the `write` method:
-
-```rust
-names.write().push("Tiger");
-```
-
-If you don't want to re-render the component when names is updated, then we can use the `write_silent` method:
-
-```rust
-names.write_silent().push("Transmogrifier");
-```
-
-Again, like `UseState`, the `UseRef` handle is clonable into async contexts:
-
-
-```rust
-// infinitely push calvin into the list
-cx.spawn({
-    to_owned![names]; 
-    async move {
-        loop {
-            wait_ms(100).await;
-            names.write().push("Calvin");
-        }
-    }
-})
-```

+ 8 - 8
docs/guide/src/interactivity/index.md

@@ -108,7 +108,7 @@ There are a few different approaches to choosing when to update your state. You
 
 When responding to user-triggered events, we'll want to "listen" for an event on some element in our component.
 
-For example, let's say we provide a button to generate a new post. Whenever the user clicks the button, they get a new post. To achieve this functionality, we'll want to attach a function to the `on_click` method of `button`. Whenever the button is clicked, our function will run, and we'll get new Post data to work with.
+For example, let's say we provide a button to generate a new post. Whenever the user clicks the button, they get a new post. To achieve this functionality, we'll want to attach a function to the `onclick` method of `button`. Whenever the button is clicked, our function will run, and we'll get new Post data to work with.
 
 ```rust
 fn App(cx: Scope)-> Element {
@@ -116,7 +116,7 @@ fn App(cx: Scope)-> Element {
 
     cx.render(rsx!{
         button {
-            on_click: move |_| set_post(PostData::random())
+            onclick: move |_| set_post(PostData::random())
             "Generate a random post"
         }
         Post { props: &post }
@@ -128,10 +128,10 @@ We'll dive much deeper into event listeners later.
 
 ### Updating state asynchronously
 
-We can also update our state outside of event listeners with `futures` and `coroutines`. 
+We can also update our state outside of event listeners with `futures` and `coroutines`.
 
 - `Futures` are Rust's version of promises that can execute asynchronous work by an efficient polling system. We can submit new futures to Dioxus either through `push_future` which returns a `TaskId` or with `spawn`.
-- `Coroutines` are asynchronous blocks of our component that have the ability to cleanly interact with values, hooks, and other data in the component. 
+- `Coroutines` are asynchronous blocks of our component that have the ability to cleanly interact with values, hooks, and other data in the component.
 
 Since coroutines and Futures stick around between renders, the data in them must be valid for the `'static` lifetime. We must explicitly declare which values our task will rely on to avoid the `stale props` problem common in React.
 
@@ -157,7 +157,7 @@ fn App(cx: Scope)-> Element {
 }
 ```
 
-Using asynchronous code can be difficult! This is just scratching the surface of what's possible. We have an entire chapter on using async properly in your Dioxus Apps. We have an entire section dedicated to using `async` properly later in this book.
+Using asynchronous code can be difficult! This is just scratching the surface of what's possible. We have an entire chapter on using async properly in your Dioxus Apps.
 
 ### How do I tell Dioxus that my state changed?
 
@@ -173,9 +173,9 @@ With these building blocks, we can craft new hooks similar to `use_state` that l
 
 In general, Dioxus should be plenty fast for most use cases. However, there are some rules you should consider following to ensure your apps are quick.
 
-- 1) **Don't call set_state _while rendering_**. This will cause Dioxus to unnecessarily re-check the component for updates or enter an infinite loop.
-- 2) **Break your state apart into smaller sections.** Hooks are explicitly designed to "unshackle" your state from the typical model-view-controller paradigm, making it easy to reuse useful bits of code with a single function.
-- 3) **Move local state down**. Dioxus will need to re-check child components of your app if the root component is constantly being updated. You'll get best results if rapidly-changing state does not cause major re-renders.
+1) **Don't call set_state _while rendering_**. This will cause Dioxus to unnecessarily re-check the component for updates or enter an infinite loop.
+2) **Break your state apart into smaller sections.** Hooks are explicitly designed to "unshackle" your state from the typical model-view-controller paradigm, making it easy to reuse useful bits of code with a single function.
+3) **Move local state down**. Dioxus will need to re-check child components of your app if the root component is constantly being updated. You'll get best results if rapidly-changing state does not cause major re-renders.
 
 <!-- todo: link when the section exists
 Don't worry - Dioxus is fast. But, if your app needs *extreme performance*, then take a look at the `Performance Tuning` in the `Advanced Guides` book.

+ 10 - 2
docs/guide/src/interactivity/lifecycles.md

@@ -1,3 +1,11 @@
-# Lifecycle, updates, and effects
+# Effects
+
+In theory, your UI code should be side-effect free. Whenever a component renders, all of its state should be prepared ahead of time. In reality, we often need to perform some sort of side effect. Possible effects include:
+
+- Logging some data
+- Pre-fetching some data
+- Attaching code to native elements
+- Cleaning up
+
+This section is organized under interactivity because effects can be important to add things like transitions, videos, and other important media.
 
-> This section is currently under construction! 🏗

+ 78 - 2
docs/guide/src/interactivity/user_input.md

@@ -1,6 +1,82 @@
 # User Input and Controlled Components
 
-Handling user input is one of the most common things your app will do, but it can be tricky
+Handling user input is one of the most common things your app will do, but it *can* be tricky.
 
+The reactive paradigm and one-way-data-flow models were all derived to solve problems that can crop up around user input handling. This section will teach you about two effective patterns for handling user input: controlled and uncontrolled inputs.
 
-> This section is currently under construction! 🏗
+## Controlled Inputs
+
+The most common approach to handling input from elements is through "controlled" inputs. With this pattern, we drive the value of the input from our state, while simultaneously updating our state from new values.
+
+This is the most common form of input handling and is widely used because it prevents the UI from being out of sync with your local state.
+
+```rust
+let name = use_state(&cx, || "bob".to_string());
+
+cx.render(rsx!{
+    input {
+        value: "{name}",
+        oninput: move |evt| name.set(evt.value.clone()),
+    }
+})
+```
+
+Why not just "bind" like in other frameworks?
+
+In a handful of cases, you don't want the inputted value to match what's rendered to the screen. Let's say we want to implement an input that converts the input to uppercase when the input matches a certain value. With binding, we're forced to share the same input and state value. By explicitly handling the oninput case, we're given the opportunity to set a *new* value.
+
+
+```rust
+let name = use_state(&cx, || "bob".to_string());
+
+cx.render(rsx!{
+    input {
+        value: "{name}",
+        oninput: move |evt| {
+            if evt.value == "tim" {
+                name.set("TIM");
+            }
+        },
+    }
+})
+```
+
+
+## Binding
+
+>! Note - binding is currently not implemented in Dioxus. This section represents a future in-progress feature.
+
+Because the above pattern is so common, we have an additional attribute called "bind" which is essentially a shorthand for our code above.
+
+Bind just connects an oninput to a `UseState` and is implemented through the signal system.
+
+```rust
+let name = use_state(&cx, || "bob".to_string());
+
+cx.render(rsx!{
+    input { bind: name }
+})
+```
+
+## Uncontrolled Inputs
+
+When working with large sets of inputs, you might be quickly tired of creating `use_state` for each value. Additionally, the pattern of one `use_state` per interaction might deteriorate when you need to have a flexible number of inputs. In these cases, we use "uncontrolled" inputs. Here, we don't drive the value of the input from the `use_state`, choosing to leave it in an "uncontrolled" state.
+
+This approach can be more performant and more flexible, but more prone to UI inconsistencies than its controlled counterpart.
+
+To use the "uncontrolled" pattern, we simply omit setting the value of the input. Instead, we can react to the change directly on the input itself, or from a form element higher up in the tree.
+
+For this example, we don't attach any `use_state` handles into the labels. Instead, we simply attach an `oninput` handler to the form element. This will run each time any of the child inputs change, allowing us to perform tasks like form validation.
+
+```rust
+form {
+    oninput: move |evt| {
+        if !validate_input(evt.values) {
+            // display what errors validation resulted in
+        }
+    },
+    input { name: "name", }
+    input { name: "age", }
+    input { name: "date", }
+}
+```

+ 155 - 0
docs/guide/src/interactivity/useref.md

@@ -0,0 +1,155 @@
+# UseRef
+
+You might've noticed a fundamental limitation to `use_state`: to modify the value in-place, it must be cheaply cloneable. But what if your type is not cheap to clone?
+
+In these cases, you should reach for `use_ref` which is essentially just a glorified `Rc<RefCell<T>>` (Rust [smart pointers](https://doc.rust-lang.org/book/ch15-04-rc.html)).
+
+This provides us some runtime locks around our data, trading reliability for performance. For most cases though, you will find it hard to make `use_ref` crash.
+
+> Note: this is *not* exactly like its React counterpart since calling `write` will cause a re-render. For more React parity, use the `write_silent` method.
+
+To use the hook:
+
+```rust
+let names = use_ref(&cx, || vec!["susie", "calvin"]);
+```
+
+To read the hook values, use the `read()` method:
+
+```rust
+cx.render(rsx!{
+    ul {
+        names.read().iter().map(|name| {
+            rsx!{ "{name}" }
+        })
+    }
+})
+```
+
+And then to write into the hook value, use the `write` method:
+
+```rust
+names.write().push("Tiger");
+```
+
+If you don't want to re-render the component when names is updated, then we can use the `write_silent` method:
+
+```rust
+names.write_silent().push("Transmogrifier");
+```
+
+Again, like `UseState`, the `UseRef` handle is clonable into async contexts:
+
+
+```rust
+// infinitely push calvin into the list
+cx.spawn({
+    to_owned![names];
+    async move {
+        loop {
+            wait_ms(100).await;
+            names.write().push("Calvin");
+        }
+    }
+})
+```
+
+## Using UseRef for complex state
+
+The best use case of `use_ref` is to manage "complex" data local to your component. This should be things like large structs, collections, queues, state machines, and other data where cloning would be expensive.
+
+
+```rust
+let val = use_ref(&cx, || vec![1, 3, 3, 7]);
+let val = use_ref(&cx, || (0..10000).collect::<Vec<_>x>());
+let val = use_ref(&cx, || Configuration {
+    a: "asdasd",
+    // .. more complex fields
+});
+```
+
+UseRef can be sent down into child components too.
+
+UseRef memoizes with itself, performing a cheap pointer comparison. If the UseRef handle is the same, then the component can be memoized.
+
+```rust
+
+fn app(cx: Scope) -> Element {
+    let val = use_ref(&cx, || 0);
+
+    cx.render(rsx!{
+        Child { val: val.clone() }
+    })
+}
+
+#[inline_props]
+fn Child(cx: Scope, val: UseRef<i32>) -> Element {
+    // ...
+}
+```
+
+## Using UseRef with "models"
+
+One option for state management that UseRef enables is the development of a "model" for your components. This particular pattern enables you to model your state with regular structs.
+
+For instance, our calculator example uses a struct to model the state.
+
+```rust
+
+struct Calculator {
+    display_value: String,
+    operator: Option<Operator>,
+    waiting_for_operand: bool,
+    cur_val: f64,
+}
+```
+
+Our component is really simple - we just call `use_ref` to get an initial calculator state.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let state = use_ref(&cx, Calculator::new);
+
+    cx.render(rsx!{
+        // the rendering code
+    })
+}
+```
+
+In our UI, we can then use `read` and a helper method to get data out of the model.
+
+```rust
+// Our accessor method
+impl Calculator {
+    fn formatted_display(&self) -> String {
+        self.display_value
+            .parse::<f64>()
+            .unwrap()
+            .separated_string()
+    }
+}
+
+// And then in the UI
+cx.render(rsx!{
+    div { [state.read().formatted_display()] }
+})
+```
+
+To modify the state, we can setup a helper method and then attach it to a callback.
+
+```rust
+// our helper
+impl Calculator {
+    fn clear_display(&mut self) {
+        self.display_value = "0".to_string()
+    }
+}
+
+// our callback
+cx.render(rsx!{
+    button {
+        onclick: move |_| state.write().clear_display(),
+    }
+})
+```
+

+ 114 - 0
docs/guide/src/interactivity/usestate.md

@@ -0,0 +1,114 @@
+# Fundamental hook: `use_state`
+
+The first fundamental hook for state management is `use_state`. This particular hook is designed to work well with the entire Dioxus ecosystem including futures, children, and memoization.
+
+
+## Basic usage
+
+The simplest use case of `use_state` is a simple counter. The handle returned by `use_state` implements `Add` and `AddAssign`. Writing through `AddAssign` will automatically mark the component as dirty, forcing an update.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let count = use_state(&cx, || 0);
+
+    rsx!(cx, button { onclick: move |_| count += 1, })
+}
+```
+
+## Reference
+
+### Common ops
+
+The `use_state` hook is very similar to its React counterpart. When we use it, we get a smart pointer - essentially an `Rc<T>` that tracks when we update it.
+
+```rust
+let mut count = use_state(&cx, || 0);
+
+// then to set the count
+count += 1;
+```
+
+
+### Current value
+
+Our `count` value is more than just an integer. Because it's a smart pointer, it also implements other useful methods helpful in various contexts.
+
+For instance, we can get a handle to the current value at any time:
+
+```rust
+let current: Rc<T> = count.current();
+```
+
+Or, we can get the inner handle to set the value:
+
+```rust
+let setter: Rc<dyn Fn(T)> = count.setter();
+```
+
+### Modify
+
+Or, we can set a new value using the current value as a reference:
+
+```rust
+count.modify(|i| i + 1);
+```
+
+### `with_mut` and `make_mut`
+
+If the value is cheaply cloneable, then we can call `with_mut` to get a mutable reference to the value:
+
+```rust
+count.with_mut(|i| *i += 1);
+```
+
+Alternatively, we can call `make_mut` which gives us a `RefMut` to the underlying value:
+
+```rust
+*count.make_mut() += 1;
+```
+
+### Use in Async
+
+Plus, the `set_count` handle is cloneable into async contexts, so we can use it in futures.
+
+```rust
+// count up infinitely
+cx.spawn({
+    let count = count.clone();
+    async move {
+        loop {
+            wait_ms(100).await;
+            count += 1;
+        }
+    }
+})
+```
+
+## Using UseState for simple data
+
+The best use case of `use_state` is to manage "simple" data local to your component. This should be things like numbers, strings, small maps, and cheaply-clonable types.
+
+```rust
+let val = use_state(&cx, || 0);
+let val = use_state(&cx, || "Hello!");
+let val = use_state(&cx, || vec![1, 3, 3, 7]);
+```
+
+UseState can be sent down into child components too.
+
+You can either pass by reference to always force the child to update when the value changes, or you can clone the handle to take advantage of automatic memoization. In these cases, calling "get" will return stale data - always prefer "current" when "cloning" the UseState. This automatic memoization of UseState solves a performance problem common in React.
+
+```rust
+
+fn app(cx: Scope) -> Element {
+    let val = use_state(&cx, || 0);
+
+    cx.render(rsx!{
+        Child { val: val.clone() }
+    })
+}
+
+fn Child(cx: Scope, val: UseState<i32>) -> Element {
+    // ...
+}
+```

+ 7 - 1
docs/guide/src/setup.md

@@ -8,7 +8,7 @@ We'll learn about:
 - Suggested cargo extensions
 
 
-For platform-specific guides, check out the [Platform Specific Guides](../platforms/00-index.md).
+For platform-specific guides, check out the [Platform Specific Guides](/reference/platforms/index.md).
 
 # Setting up Dioxus
 
@@ -52,6 +52,12 @@ Webview Linux apps require WebkitGtk. When distributing, this can be part of you
 sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libappindicator3-dev
 ```
 
+When using Debian/bullseye `libappindicator3-dev` is no longer available but replaced by `libayatana-appindicator3-dev`.
+
+```
+# on Debian/bullseye use:
+sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev
+```
 
 If you run into issues, make sure you have all the basics installed, as outlined in the [Tauri docs](https://tauri.studio/en/docs/get-started/setup-linux).
 

+ 1 - 0
docs/guide/src/state/channels.md

@@ -0,0 +1 @@
+# Channels

+ 148 - 2
docs/guide/src/state/errorhandling.md

@@ -1,12 +1,158 @@
 # Error handling
 
+A selling point of Rust for web development is the reliability of always knowing where errors can occur and being forced to handle them
+
+However, we haven't talked about error handling at all in this guide! In this chapter, we'll cover some strategies in handling errors to ensure your app never crashes.
+
+
+
+## The simplest - returning None
 
 Astute observers might have noticed that `Element` is actually a type alias for `Option<VNode>`. You don't need to know what a `VNode` is, but it's important to recognize that we could actually return nothing at all:
 
 ```rust
-fn App((cx, props): Component) -> Element {
+fn App(cx: Scope) -> Element {
     None
 }
 ```
 
-> This section is currently under construction! 🏗
+This lets us add in some syntactic sugar for operations we think *shouldn't* fail, but we're still not confident enough to "unwrap" on.
+
+> The nature of `Option<VNode>` might change in the future as the `try` trait gets upgraded.
+
+```rust
+fn App(cx: Scope) -> Element {
+    // immediately return "None"
+    let name = cx.use_hook(|_| Some("hi"))?;
+}
+```
+
+## Early return on result
+
+Because Rust can't accept both Options and Results with the existing try infrastructure, you'll need to manually handle Results. This can be done by converting them into Options or by explicitly handling them.
+
+```rust
+fn App(cx: Scope) -> Element {
+    // Convert Result to Option
+    let name = cx.use_hook(|_| "1.234").parse().ok()?;
+
+
+    // Early return
+    let count = cx.use_hook(|_| "1.234");
+    let val = match count.parse() {
+        Ok(val) => val
+        Err(err) => return cx.render(rsx!{ "Parsing failed" })
+    };
+}
+```
+
+Notice that while hooks in Dioxus do not like being called in conditionals or loops, they *are* okay with early returns. Returning an error state early is a completely valid way of handling errors.
+
+
+## Match results
+
+The next "best" way of handling errors in Dioxus is to match on the error locally. This is the most robust way of handling errors, though it doesn't scale to architectures beyond a single component.
+
+To do this, we simply have an error state built into our component:
+
+```rust
+let err = use_state(&cx, || None);
+```
+
+Whenever we perform an action that generates an error, we'll set that error state. We can then match on the error in a number of ways (early return, return Element, etc).
+
+
+```rust
+fn Commandline(cx: Scope) -> Element {
+    let error = use_state(&cx, || None);
+
+    cx.render(match *error {
+        Some(error) => rsx!(
+            h1 { "An error occured" }
+        )
+        None => rsx!(
+            input {
+                oninput: move |_| error.set(Some("bad thing happened!")),
+            }
+        )
+    })
+}
+```
+
+## Passing error states through components
+
+If you're dealing with a handful of components with minimal nesting, you can just pass the error handle into child components.
+
+```rust
+fn Commandline(cx: Scope) -> Element {
+    let error = use_state(&cx, || None);
+
+    if let Some(error) = **error {
+        return cx.render(rsx!{ "An error occured" });
+    }
+
+    cx.render(rsx!{
+        Child { error: error.clone() }
+        Child { error: error.clone() }
+        Child { error: error.clone() }
+        Child { error: error.clone() }
+    })
+}
+```
+
+Much like before, our child components can manually set the error during their own actions. The advantage to this pattern is that we can easily isolate error states to a few components at a time, making our app more predictable and robust.
+
+## Going global
+
+A strategy for handling cascaded errors in larger apps is through signaling an error using global state. This particular pattern involves creating an "error" context, and then setting it wherever relevant. This particular method is not as "sophisticated" as React's error boundary, but it is more fitting for Rust.
+
+To get started, consider using a built-in hook like `use_context` and `use_context_provider` or Fermi. Of course, it's pretty easy to roll your own hook too.
+
+At the "top" of our architecture, we're going to want to explicitly declare a value that could be an error.
+
+
+```rust
+enum InputError {
+    None,
+    TooLong,
+    TooShort,
+}
+
+static INPUT_ERROR: Atom<InputError> = |_| InputError::None;
+```
+
+Then, in our top level component, we want to explicitly handle the possible error state for this part of the tree.
+
+```rust
+fn TopLevel(cx: Scope) -> Element {
+    let error = use_read(&cx, INPUT_ERROR);
+
+    match error {
+        TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
+        TooShort => return cx.render(rsx!{ "FAILED: Too Short!" }),
+        _ => {}
+    }
+}
+```
+
+Now, whenever a downstream component has an error in its actions, it can simply just set its own error state:
+
+```rust
+fn Commandline(cx: Scope) -> Element {
+    let set_error = use_set(&cx, INPUT_ERROR);
+
+    cx.render(rsx!{
+        input {
+            oninput: move |evt| {
+                if evt.value.len() > 20 {
+                    set_error(InputError::TooLong);
+                }
+            }
+        }
+    })
+}
+```
+
+This approach to error handling is best in apps that have "well defined" error states. Consider using a crate like `thiserror` or `anyhow` to simplify the generation of the error types.
+
+This pattern is widely popular in many contexts and is particularly helpful whenever your code generates a non-recoverable error. You can gracefully capture these "global" error states without panicking or mucking up state.

+ 61 - 0
docs/guide/src/state/fanout.md

@@ -0,0 +1,61 @@
+# Fanning Out
+
+One of the most reliable state management patterns in large Dioxus apps is `fan-out`. The fan-out pattern is the ideal way to structure your app to maximize code reuse, testability, and deterministic rendering.
+
+## The structure
+
+With `fan-out`, our individual components at "leaf" position of our VirtualDom are "pure", making them easily reusable, testable, and deterministic. For instance, the "title" bar of our app might be a fairly complicated component.
+
+```rust
+#[derive(Props, PartialEq)]
+struct TitlebarProps {
+    title: String,
+    subtitle: String,
+}
+
+fn Titlebar(cx: Scope<TitlebarProps>) -> Element {
+    cx.render(rsx!{
+        div {
+            class: "titlebar"
+            h1 { "{cx.props.title}" }
+            h1 { "{cx.props.subtitle}" }
+        }
+    })
+}
+```
+
+If we used global state like use_context or fermi, we might be tempted to inject our `use_read` directly into the component.
+
+```rust
+fn Titlebar(cx: Scope<TitlebarProps>) -> Element {
+    let title = use_read(&cx, TITLE);
+    let subtitle = use_read(&cx, SUBTITLE);
+
+    cx.render(rsx!{/* ui */})
+}
+```
+
+For many apps - this is a fine pattern, especially if the component is a one-off. However, if we want to reuse the component outside of this app, then we'll start to run into issues where our contexts are unavailable.
+
+## Fanning Out
+
+To enable our titlebar component to be used across apps, we want to lift our atoms upwards and out of the Titlebar component. We would organize a bunch of other components in this section of the app to share some of the same state.
+
+```rust
+fn DocsiteTitlesection(cx: Scope) {
+    let title = use_read(&cx, TITLE);
+    let subtitle = use_read(&cx, SUBTITLE);
+
+    let username = use_read(&cx, USERNAME);
+    let points = use_read(&cx, POINTS);
+
+    cx.render(rsx!{
+        TitleBar { title: title, subtitle: subtitle }
+        UserBar { username: username, points: points }
+    })
+}
+```
+
+This particular wrapper component unfortunately cannot be reused across apps. However, because it simply wraps other real elements, it doesn't have to. We are free to reuse our TitleBar and UserBar components across apps with ease. We also know that this particular component is plenty performant because the wrapper doesn't have any props and is always memoized. The only times this component re-renders is when any of the atoms change.
+
+This is the beauty of Dioxus - we always know where our components are likely to be re-rendered. Our wrapper components can easily prevent any large re-renders by simply memoizing their components. This system might not be as elegant or precise as signal systems found in libraries like Sycamore or SolidJS, but it is quite ergonomic.

+ 110 - 0
docs/guide/src/state/fermi.md

@@ -0,0 +1,110 @@
+# Fermi
+
+After having covered local and global state, you're definitely ready to start building some complex Dioxus apps. Before you get too far, check out the Fermi crate. Fermi makes it dead-easy to manage global state and scales to the largest of apps.
+
+## What is Fermi for?
+
+If you're building an app that has scaled past a few small components, then it'll be worth sketching out and organizing your app's state. Fermi makes it easy to transition from a simple app that relies on `use_state` to an app with dozens of components.
+
+> To put it simply - Fermi is the ideal crate for managing global state in your Dioxus app.
+
+
+## How do I use it?
+
+To add fermi to your project, simply add the "fermi" feature to your Dioxus dependency.
+
+```toml
+[dependencies]
+dioxus = { version = "0.2", features = ["desktop", "fermi"] }
+```
+
+Fermi is built on the concept of "atoms" of global state. Instead of bundling all our state together in a single mega struct, we actually chose to implement it piece-by-piece with functions.
+
+Each piece of global state in your app is represented by an "atom."
+
+```rust
+static TITLE: Atom<String> = |_| "Defualt Title".to_string();
+```
+
+This atom can be then used the with the `use_atom` hook as a drop-in replacement for `use_state`.
+
+```rust
+static TITLE: Atom<String> = |_| "Defualt Title".to_string();
+
+fn Title(cx: Scope) -> Element {
+    let title = use_atom(&cx, TITLE);
+
+    cx.render(rsx!{
+        button { onclick: move |_| title.set("new title".to_string()) }
+    })
+}
+```
+
+However, Fermi really becomes useful when we want to share the value between two different components.
+
+```rust
+static TITLE: Atom<String> = |_| "Defualt Title".to_string();
+
+fn TitleBar(cx: Scope) -> Element {
+    let title = use_atom(&cx, TITLE);
+
+    rsx!{cx, button { onclick: move |_| title.set("titlebar title".to_string()) } }
+}
+
+fn TitleCard(cx: Scope) -> Element {
+    let title = use_atom(&cx, TITLE);
+
+    rsx!{cx, button { onclick: move |_| title.set("title card".to_string()) } }
+}
+```
+
+These two components can get and set the same value!
+
+
+## Use with collections
+
+Fermi gets *really* powerful when used to manage collections of data. Under the hood, Fermi uses immutable collections and tracks reads and writes of individual keys. This makes it easy to implement things like lists and infinite posts with little performance penalty. It also makes it really easy to refactor our app and add new fields.
+
+```rust
+static NAMES: AtomRef<Uuid, String> = |builder| {};
+static CHECKED: AtomRef<Uuid, bool> = |builder| {};
+static CREATED: AtomRef<Uuid, Instant> = |builder| {};
+```
+
+To use these collections:
+
+```rust
+#[inline_props]
+fn Todo(cx: Scope, id: Uuid) -> Element {
+    let name = use_atom(&cx, NAMES.select(id));
+    let checked = use_atom(&cx, CHECKED.select(id));
+    let created = use_atom(&cx, CREATED.select(id));
+
+    // or
+
+    let (name, checked, created) = use_atom(&cx, (NAMES, CHECKED, CREATED).select(id));
+}
+```
+
+This particular pattern might seem strange at first - "why isn't all of our state under one struct?" - but eventually shows its worth when dealing with large amounts of data. By composing collections together, we can get get the perks of the Entity-Component-System architecture in our Dioxus apps. Performance is quite predictable here and easy to trace.
+
+## AtomRef
+
+Much like `use_ref` can be used to manage complex state locally, `AtomRef` can be used to manage complex global state. `AtomRef` is basically a global `Rc<RefCell<T>>` with mutation tracking.
+
+It too serves as a basic replacement for `use_ref`:
+
+```rust
+fn Todo(cx: Scope) -> Element {
+    let cfg = use_atom_ref(&cx, CFG);
+
+    cfg.write().enable_option();
+}
+
+```
+
+## Future Reading
+
+This guide is meant just to be an overview of Fermi. This page is just a short advertisement for what we consider the best state management solution available today for Dioxus apps.
+
+For further reading, check out the [crate itself](https://github.com/DioxusLabs/dioxus/tree/master/packages/fermi)!

+ 22 - 12
docs/guide/src/state/index.md

@@ -1,28 +1,38 @@
 # Managing State
 
-Every app you'll build with Dioxus will have some sort of state that needs to be maintained and updated as your users interact with it. However, managing state can be particular challenging at times, and is frequently the source of bugs in many GUI frameworks.
+Every app you'll build with Dioxus will have some sort of state that needs to be maintained and updated as your users interact with it. However, managing state can be particularly challenging at times, and is frequently the source of bugs in many GUI frameworks.
 
-In this chapter, we'll cover the various ways to manage state, the appropriate terminology, various patterns, and then take an overview
+In this chapter, we'll cover the various ways to manage state, the appropriate terminology, various patterns, and some problems you might run into.
 
-## Terminology 
 
+## The Problem
 
-> This section is currently under construction! 🏗
+Why do people say state management is so difficult? What does it mean?
 
+Generally, state management is the code you need to write to ensure that your app renders the *correct* content. If the user inputs a name, then you need to display the appropriate response - like alerts, validation, and disable/enable various elements on the page. Things can quickly become tricky if you need loading screens and cancellable tasks.
 
+For the simplest of apps, all of your state can enter the app from the root props. This is common in server-side rendering - we can collect all of the required state *before* rendering the content.
 
+```rust
+let all_content = get_all_content().await;
 
-## Important hook: `use_state`
+let output = dioxus::ssr::render_lazy(rsx!{
+    div {
+        RenderContent { content: all_content }
+    }
+});
+```
 
+With this incredibly simple setup, it is highly unlikely that you'll have rendering bugs. There simply is barely any state to manage.
 
+However, most of your apps will store state inside of the Dioxus VirtualDom - either through local state or global state.
 
 
+## Your options
 
-## Important hook: `use_ref`
+To deal with complexity, you have a couple of options:
 
-
-
-
-## `provide_context` and `consume_context`
-
-## Terminology
+- Refactor state out of shared state and into reusable components and hooks.
+- Lift state upwards to be spread across multiple components (fan out).
+- Use the Context API to share state globally.
+- Use a dedicated state management solution like Fermi.

+ 128 - 2
docs/guide/src/state/liftingstate.md

@@ -1,4 +1,130 @@
-# Lifting State
+# Lifting State and Fanning Out
 
+Maintaining state local to components doesn't always work.
 
-> This section is currently under construction! 🏗
+One of the most reliable state management patterns in large Dioxus apps is to `lift-up` and `fan-out`. Lifting up and fanning-out state is the ideal way to structure your app to maximize code reuse, testability, and deterministic rendering.
+
+
+## Lifting State
+
+When building complex apps with Dioxus, the best approach is to start by placing your state and an UI all within a single component. Once your component has passed a few hundred lines, then it might be worth refactoring it into a few smaller components.
+
+Here, we're now challenged with how to share state between these various components.
+
+Let's say we refactored our component to separate an input and a display.
+
+```rust
+fn app(cx: Scope) -> Element {
+    cx.render(rsx!{
+        Title {}
+        Input {}
+    })
+}
+```
+
+Whenever a value is inputted in our `Input` component, we need to somehow propagate those changes into the `Title` component.
+
+A quick-and-dirty solution - which works for many apps - is to simply share a UseState between the two components.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let text = use_state(&cx, || "default".to_string());
+
+    cx.render(rsx!{
+        Title { text: text.clone() }
+        Input { text: text.clone() }
+    })
+}
+```
+
+> Note: since we `Cloned` our `text` `UseState` handle, both `Title` and `Input` will be memoized.
+
+Here, we've "lifted" state out of our `Input` component and brought it up to the closest shared ancestor. In our input component, we can directly use this UseState handle as if it had been defined locally:
+
+```rust
+#[inline_props]
+fn Input(cx: Scope, text: UseState<String>) -> Element {
+    cx.render(rsx!{
+        input { oninput: move |evt| text.set(evt.value.clone()) }
+    })
+}
+```
+Similarly, our `Title` component would be straightforward:
+
+```rust
+#[inline_props]
+fn Title(cx: Scope, text: UseState<String>) -> Element {
+    cx.render(rsx!{
+        h1 { "{text}" }
+    })
+}
+```
+
+For more complicated use cases, we can take advantage of the EventHandler coercion talked about before to pass in any callback. Recall that fields on components that start with "on" are automatically "upgraded" into an `EventHandler` at the call site.
+
+This lets us abstract over the exact type of state being used to store the data.
+
+For the `Input` component, we would simply add a new `oninput` field:
+
+```rust
+#[inline_props]
+fn Input<'a>(cx: Scope<'a>, oninput: EventHandler<'a, String>) -> Element {
+    cx.render(rsx!{
+        input { oninput: move |evt| oninput.call(evt.value.clone()), }
+    })
+}
+```
+
+For our `Title` component, we could also abstract it to take any `&str`:
+
+```rust
+#[inline_props]
+fn Title<'a>(cx: Scope<'a>, text: &'a str) -> Element {
+    cx.render(rsx!{
+        h1 { "{text}" }
+    })
+}
+```
+
+## Fanning Out
+
+As your app grows and grows, you might need to start pulling in global state to avoid prop drilling. This tends to solve a lot of problems, but generates even more.
+
+For instance, let's say we built a beautiful `Title` component. Instead of passing props in, we instead are using a `use_read` hook from Fermi.
+
+```rust
+fn Title(cx: Scope) -> Element {
+    let title = use_read(&cx, TITLE);
+
+    cx.render(rsx!{
+        h1 { "{title}" }
+    })
+}
+```
+
+This is great - all is well in the world. We get precise updates, automatic memoization, and a solid abstraction. But, what happens when we want to reuse this component in another project? This component is now deeply intertwined with our global state - which might not be the same in another app.
+
+In this case, we want to "lift" our global state out of "view" components.  With `lifting`, our individual components at "leaf" position of our VirtualDom are "pure", making them easily reusable, testable, and deterministic.
+
+To enable our title component to be used across apps, we want to lift our atoms upwards and out of the Title component. We would organize a bunch of other components in this section of the app to share some of the same state.
+
+```rust
+fn DocsiteTitlesection(cx: Scope) {
+    // Use our global state in a wrapper component
+    let title = use_read(&cx, TITLE);
+    let subtitle = use_read(&cx, SUBTITLE);
+
+    let username = use_read(&cx, USERNAME);
+    let points = use_read(&cx, POINTS);
+
+    // and then pass our global state in from the outside
+    cx.render(rsx!{
+        Title { title: title.clone(), subtitle: subtitle.clone() }
+        User { username: username.clone(), points: points.clone() }
+    })
+}
+```
+
+This particular wrapper component unfortunately cannot be reused across apps. However, because it simply wraps other real elements, it doesn't have to. We are free to reuse our TitleBar and UserBar components across apps with ease. We also know that this particular component is plenty performant because the wrapper doesn't have any props and is always memoized. The only times this component re-renders is when any of the atoms change.
+
+This is the beauty of Dioxus - we always know where our components are likely to be re-rendered. Our wrapper components can easily prevent any large re-renders by simply memoizing their components. This system might not be as elegant or precise as signal systems found in libraries like Sycamore or SolidJS, but it is quite ergonomic.

+ 107 - 1
docs/guide/src/state/localstate.md

@@ -1,4 +1,110 @@
 # Local State
 
+The first step to dealing with complexity in your app is to refactor your state to be purely local. This encourages good code reuse and prevents leakage of abstractions across component boundaries.
+
+## What it looks like
+
+Let's say we're managing the state for a list of Todos. Whenever we edit the todo, we want the list to update. We might've started building our app but putting everything into a single `use_ref`.
+
+```rust
+struct Todo {
+    contents: String,
+    is_hovered: bool,
+    is_editing: bool,
+}
+
+let todos = use_ref(&cx, || vec![Todo::new()]);
+
+cx.render(rsx!{
+    ul {
+        todos.read().iter().enumerate().map(|(id, todo)| rsx!{
+            li {
+                onhover: move |_| *todos.write()[id].is_hovered = true,
+                h1 { "{todo.contents}" }
+            }
+        })
+    }
+})
+```
+
+As shown above, whenever the todo is hovered, we want to set its state:
+
+```rust
+todos.write()[0].is_hovered = true;
+```
+
+As the amount of interactions goes up, so does the complexity of our state. Should the "hover" state really be baked into our data model?
+
+Instead, let's refactor our Todo component to handle its own state:
+
+```rust
+#[inline_props]
+fn Todo<'a>(cx: Scope, todo: &'a Todo) -> Element {
+    let is_hovered = use_state(&cx, || false);
+
+    cx.render(rsx!{
+        li {
+            h1 { "{todo.contents}" }
+            onhover: move |_| is_hovered.set(true),
+        }
+    })
+}
+```
+
+Now, we can simplify our Todo data model to get rid of local UI state:
+
+```rust
+struct Todo {
+    contents: String,
+}
+```
+
+This is not only better for encapsulation and abstraction, but it's only more performant! Whenever a Todo is hovered, we won't need to re-render *every* Todo again - only the Todo that's currently being hovered.
+
+
+Wherever possible, you should try to refactor the "view" layer *out* of your data model.
+
+## Immutability
+
+Storing all of your state inside a `use_ref` might be tempting. However, you'll quickly run into an issue where the `Ref` provided by `read()` "does not live long enough." An indeed - you can't return locally-borrowed value into the Dioxus tree.
+
+In these scenarios consider breaking your `use_ref` into individual `use_state`s.
+
+You might've started modeling your component with a struct and use_ref
+
+```rust
+struct State {
+    count: i32,
+    color: &'static str,
+    names: HashMap<String, String>
+}
+
+// in the component
+let state = use_ref(&cx, State::new)
+```
+
+The "better" approach for this particular component would be to break the state apart into different values:
+
+```rust
+let count = use_state(&cx, || 0);
+let color = use_state(&cx, || "red");
+let names = use_state(&cx, HashMap::new);
+```
+
+You might recognize that our "names" value is a HashMap - which is not terribly cheap to clone every time we update its value. To solve this issue, we *highly* suggest using a library like [`im`](https://crates.io/crates/im) which will take advantage of structural sharing to make clones and mutations much cheaper.
+
+When combined with the `make_mut` method on `use_state`, you can get really succinct updates to collections:
+
+```rust
+let todos = use_state(&cx, im_rc::HashMap::default);
+
+todos.make_mut().insert("new todo", Todo {
+    contents: "go get groceries",
+});
+```
+
+## Moving on
+
+This particular local patterns are powerful but is not a cure-all for state management problems. Sometimes your state problems are much larger than just staying local to a component.
+
 
-> This section is currently under construction! 🏗

+ 86 - 0
docs/guide/src/state/router.md

@@ -0,0 +1,86 @@
+# Router
+
+In many of your apps, you'll want to have different "scenes". For a webpage, these scenes might be the different webpages with their own content.
+
+You could write your own scene management solution - quite simply too. However, to save you the effort, Dioxus supports a first-party solution for scene management called Dioxus Router.
+
+
+## What is it?
+
+For an app like the Dioxus landing page (https://dioxuslabs.com), we want to have different pages. A quick sketch of an app would be something like:
+
+- Homepage
+- Blog
+- Example showcase
+
+Each of these scenes is independent - we don't want to render both the homepage and blog at the same time.
+
+This is where the router crates come in handy. To make sure we're using the router, simply add the `"router"` feature to your dioxus dependency.
+
+```toml
+[dependencies]
+dioxus = { version = "0.2", features = ["desktop", "router"] }
+```
+
+
+## Using the router
+
+Unlike other routers in the Rust ecosystem, our router is built declaratively. This makes it possible to compose our app layout simply by arranging components.
+
+```rust
+rsx!{
+    Router {
+        Route { to: "/home", Home {} }
+        Route { to: "/blog", Blog {} }
+    }
+}
+```
+
+Whenever we visit this app, we will get either the Home component or the Blog component rendered depending on which route we enter at. If neither of these routes match the current location, then nothing will render.
+
+We can fix this one of two ways:
+
+- A fallback 404 page
+
+```rust
+rsx!{
+    Router {
+        Route { to: "/home", Home {} }
+        Route { to: "/blog", Blog {} }
+        Route { to: "", NotFound {} }
+    }
+}
+```
+
+
+- Redirect 404 to home
+
+```rust
+rsx!{
+    Router {
+        Route { to: "/home", Home {} }
+        Route { to: "/blog", Blog {} }
+        Redirect { from: "", to: "/home" }
+    }
+}
+```
+
+## Links
+
+For our app to navigate these routes, we can provide clickable elements called Links. These simply wrap `<a>` elements that, when clicked, navigate the app to the given location.
+
+
+```rust
+rsx!{
+    Link {
+        to: "/home",
+        "Go home!"
+    }
+}
+```
+
+## More reading
+
+This page is just meant to be a very brief overview of the router to show you that there's a powerful solution already built for a very common problem. For more information about the router, definitely check out its book or check out some of the examples.
+
+The router has its own documentation! [Available here](https://dioxuslabs.com/router/guide/).

+ 61 - 3
docs/guide/src/state/sharedstate.md

@@ -1,7 +1,65 @@
 # Global State
 
+If your app has finally gotten large enough where passing values through the tree ends up polluting the intent of your code, then it might be time to turn to global state.
 
-cx.provide_context()
-cx.consume_context()
+In Dioxus, global state is shared through the Context API. This guide will show you how to use the Context API to simplify state management.
 
-> This section is currently under construction! 🏗
+## Provide Context and Consume Context
+
+The simplest way of retrieving shared state in your app is through the Context API. The Context API allows you to provide and consume an item of state between two components.
+
+Whenever a component provides a context, it is then accessible to any child components.
+
+> Note: parent components cannot "reach down" and consume state from below their position in the tree.
+
+The terminology here is important: `provide` context means that the component will expose state and `consume` context means that the child component can acquire a handle to state above it.
+
+Instead of using keys or statics, Dioxus prefers the `NewType` pattern to search for parent state. This means each state you expose as a context should be its own unique type.
+
+In practice, you'll have a component that exposes some state:
+
+
+```rust
+#[derive(Clone)]
+struct Title(String);
+
+fn app(cx: Scope) -> Element {
+    cx.use_hook(|_| {
+        cx.provide_context(Title("Hello".to_string()));
+    });
+
+    cx.render(rsx!{
+        Child {}
+    })
+}
+```
+
+And then in our component, we can consume this state at any time:
+
+```rust
+fn Child(cx: Scope) -> Element {
+    let name = cx.consume_context::<Title>();
+
+    //
+}
+```
+
+Note: calling "consume" state can be a rather expensive operation to perform during each render. Prefer to consume state within a `use_hook`:
+
+```rust
+fn Child(cx: Scope) -> Element {
+    // cache our "consume_context" operation
+    let name = cx.use_hook(|_| cx.consume_context::<Title>());
+}
+```
+
+All `Context` must be cloned - the item will be cloned into each call of `consume_context`. To make this operation cheaper, consider wrapping your type in an `Rc` or `Arc`.
+
+
+<!-- ## Coroutines
+
+The `use_coroutine` hook  -->
+
+<!-- # `use_context` and `use_context_provider`
+
+These -->

+ 367 - 0
docs/posts/release-0-2-0.md

@@ -0,0 +1,367 @@
+# Dioxus v0.2 Release: TUI, Router, Fermi, and Tooling
+
+> March 9, 2022
+
+Thanks to these amazing folks for their financial support on OpenCollective:
+
+- [@t1m0t](https://github.com/t1m0t)
+- [@alexkirsz](https://github.com/t1m0t)
+- [@freopen](https://github.com/freopen)
+- [@DannyMichaels](https://github.com/DannyMichaels)
+- [@SweetLittleMUV](https://github.com/Fatcat560)
+
+Thanks to these amazing folks for their code contributions:
+
+- [@mrxiaozhuox](https://github.com/mrxiaozhuox)
+- [@autarch](https://github.com/autarch)
+- [@FruitieX](https://github.com/FruitieX)
+- [@t1m0t](https://github.com/t1m0t)
+- [@Demonthos](https://github.com/Demonthos)
+- [@oovm](https://github.com/oovm)
+- [@6asaaki](https://github.com/6asaaki)
+
+
+Just over two months in, and we already a ton of awesome changes to Dioxus!
+
+Dioxus is a recently-released library for building interactive user interfaces (GUI) with Rust. It is built around a Virtual DOM, making it portable for the web, desktop, server, mobile, and more. Dioxus looks and feels just like React, so if you know React, then you'll feel right at home.
+
+```rust
+fn app(cx: Scope) -> Element {
+    let mut count = use_state(&cx, || 0);
+
+    cx.render(rsx! {
+        h1 { "Count: {count}" }
+        button { onclick: move |_| count += 1, "+" }
+        button { onclick: move |_| count -= 1, "-" }
+    })
+}
+```
+
+# What's new?
+
+A *ton* of stuff happened in this release; 550+ commits, 23 contributors, 2 minor releases, and 6 backers on Open Collective.
+
+Some of the major new features include:
+
+- We now can render into the terminal, similar to Ink.JS - a huge thanks to [@Demonthos](https://github.com/Demonthos)
+- We have a new router in the spirit of React-Router [@autarch](https://github.com/autarch)
+- We now have Fermi for global state management in the spirit of [Recoil.JS](https://recoiljs.org)
+- Our desktop platform got major upgrades, getting closer to parity with Electron [@mrxiaozhuox](https://github.com/mrxiaozhuox)
+- Our CLI tools now support HTML-to-RSX translation for converting 3rd party HTML into Dioxus [@mrxiaozhuox](https://github.com/mrxiaozhuox)
+- Dioxus-Web is sped up by 2.5x with JS-based DOM manipulation (3x faster than React)
+
+We also fixed and improved a bunch of stuff - check out the full list down below.
+
+
+## A New Renderer: Your terminal!
+
+When Dioxus was initially released, we had very simple support for logging Dioxus elements out as TUI elements. In the past month or so, [@Demonthos](https://github.com/Demonthos) really stepped up and made the new crate a reality.
+
+
+![Imgur](https://i.imgur.com/GL7uu3r.png)
+
+The new TUI renderer even supports mouse movements, keyboard input, async tasks, borders, and a ton more.
+
+<video controls autoplay muted>
+    <source src="https://i.imgur.com/q25tZST.mp4" type="video/mp4">
+</vido>
+
+
+
+## New Router
+
+We totally revamped the router, switching away from the old yew-router approach to the more familiar [React-Router](http://reactrouter.com). It's less type-safe but provides more flexibility and support for beautiful URLs.
+
+Apps with routers are *really* simple now. It's easy to compose the "Router", a "Route", and "Links" to define how your app is laid out:
+
+```rust
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            onchange: move |_| log::info!("Route changed!"),
+            ul {
+                Link { to: "/",  li { "Go home!" } }
+                Link { to: "users",  li { "List all users" } }
+                Link { to: "blog", li { "Blog posts" } }
+            }
+            Route { to: "/", "Home" }
+            Route { to: "/users", "User list" }
+            Route { to: "/users/:name", User {} }
+            Route { to: "/blog", "Blog list" }
+            Route { to: "/blog/:post", BlogPost {} }
+            Route { to: "", "Err 404 Route Not Found" }
+        }
+    })
+}
+```
+
+We're also using hooks to parse the URL parameters and segments so you can interact with the router from anywhere deeply nested in your app.
+
+```rust
+#[derive(Deserialize)]
+struct Query { name: String }
+
+fn BlogPost(cx: Scope) -> Element {
+    let post = use_route(&cx).segment("post")?;
+    let query = use_route(&cx).query::<Query>()?;
+
+    cx.render(rsx!{
+        "Viewing post {post}"
+        "Name selected: {query}"
+    })
+}
+```
+
+Give a big thanks to [@autarch](https://github.com/autarch) for putting in all the hard work to make this new router a reality.
+
+The Router guide is [available here](https://dioxuslabs.com/nightly/router/) - thanks to [@dogedark](https://github.com/dogedark).
+
+## Fermi for Global State Management
+
+Managing state in your app can be challenging. Building global state management solutions can be even more challenging. For the first big attempt at building a global state management solution for Dioxus, we chose to keep it simple and follow in the footsteps of the [Recoil.JS](http://recoiljs.org) project.
+
+Fermi uses the concept of "Atoms" for global state. These individual values can be get/set from anywhere in your app. Using state with Fermi is basically as simple as `use_state`.
+
+```rust
+// Create a single value in an "Atom"
+static TITLE: Atom<&str> = |_| "Hello";
+
+// Read the value from anywhere in the app, subscribing to any changes
+fn app(cx: Scope) -> Element {
+    let title = use_read(&cx, TITLE);
+    cx.render(rsx!{
+        h1 { "{title}" }
+        Child {}
+    })
+}
+
+// Set the value from anywhere in the app
+fn Child(cx: Scope) -> Element {
+    let set_title = use_set(&cx, TITLE);
+    cx.render(rsx!{
+        button {
+            onclick: move |_| set_title("goodbye"),
+            "Say goodbye"
+        }
+    })
+}
+```
+
+## Inline Props Macro
+
+For internal components, explicitly declaring props structs can become tedious. That's why we've built the new `inline_props` macro. This macro lets you inline your props definition right into your component function arguments.
+
+Simply add the `inline_props` macro to your component:
+```rust
+#[inline_props]
+fn Child<'a>(
+    cx: Scope,
+    name: String,
+    age: String,
+    onclick: EventHandler<'a, ClickEvent>
+) -> Element {
+    cx.render(rsx!{
+        button {
+            "Hello, {name}"
+            "You are {age} years old"
+            onclick: move |evt| onclick.call(evt)
+        }
+    })
+}
+```
+
+You won't be able to document each field or attach attributes so you should refrain from using it in libraries.
+
+## Props optional fields
+
+Sometimes you don't want to specify *every* value in a component's props, since there might a lot. That's why the `Props` macro now supports optional fields. You can use a combination of `default`, `strip_option`, and `optional` to tune the exact behavior of properties fields.
+
+```rust
+#[derive(Props, PartialEq)]
+struct ChildProps {
+    #[props(default = "client")]
+    name: String,
+
+    #[props(default)]
+    age: Option<u32>,
+
+    #[props(optional)]
+    age: Option<u32>,
+}
+
+// then to use the accompanying component
+rsx!{
+    Child {
+        name: "asd",
+    }
+}
+```
+
+## Dioxus Web Speed Boost
+
+We've changed how DOM patching works in Dioxus-Web; now, all of the DOM manipulation code is written in TypeScript and shared between our web, desktop, and mobile runtimes.
+
+On an M1-max, the "create-rows" operation used to take 45ms. Now, it takes a mere 17ms - 3x faster than React. We expect an upcoming optimization to bring this number as low as 3ms.
+
+Under the hood, we have a new string interning engine to cache commonly used tags and values on the Rust <-> JS boundary, resulting in significant performance improvements.
+
+Overall, Dioxus apps are even more snappy than before.
+
+
+Before and after:
+![Before and After](https://imgur.com/byTBGlO.png)
+
+
+## Dioxus Desktop Window Context
+
+A very welcome change, thanks AGAIN to [@mrxiaozhuox](https://github.com/mrxiaozhuox) is support for imperatively controlling the desktop window from your Dioxus code.
+
+A bunch of new methods were added:
+- Minimize and maximize window
+- Close window
+- Focus window
+- Enable devtools on the fly
+
+And more!
+
+In addition, Dioxus Desktop now autoresolves asset locations, so you can easily add local images, JS, CSS, and then bundle it into an .app without hassle.
+
+You can now build entirely borderless desktop apps:
+
+![img](https://i.imgur.com/97zsVS1.png)
+
+## CLI Tool
+
+Thanks to the amazing work by [@mrxiaozhuox](https://github.com/mrxiaozhuox), our CLI tool is fixed and working better than ever. The Dioxus-CLI sports a new development server, an HTML to RSX translation engine, a `cargo fmt`-style command, a configuration scheme, and much more.
+
+Unlike its counterpart, `Trunk.rs`, the dioxus-cli supports running examples and tests, making it easier to test web-based projects and showcase web-focused libraries.
+
+## Async Improvements
+
+Working with async isn't the easiest part of Rust. To help improve things, we've upgraded async support across the board in Dioxus.
+
+
+First, we upgraded the `use_future` hook. It now supports dependencies, which let you regenerate a future on the fly as its computed values change. It's never been easier to add datafetching to your Rust Web Apps:
+
+```rust
+fn RenderDog(cx: Scope, breed: String) -> Element {
+    let dog_request = use_future(&cx, (breed,), |(breed,)| async move {
+        reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
+            .await
+            .unwrap()
+            .json::<DogApi>()
+            .await
+    });
+
+    cx.render(match dog_request.value() {
+        Some(Ok(url)) => rsx!{ img { url: "{url}" } },
+        Some(Err(url)) => rsx!{ span { "Loading dog failed" }  },
+        None => rsx!{ "Loading dog..." }
+    })
+}
+```
+
+Additionally, we added better support for coroutines. You can now start, stop, resume, and message with asynchronous tasks. The coroutine is automatically exposed to the rest of your app via the Context API. For the vast majority of apps, Coroutines can satisfy all of your state management needs:
+
+```rust
+fn App(cx: Scope) -> Element {
+    let sync_task = use_coroutine(&cx, |rx| async move {
+        connect_to_server().await;
+        let state = MyState::new();
+
+        while let Some(action) = rx.next().await {
+            reduce_state_with_action(action).await;
+        }
+    });
+
+    cx.render(rsx!{
+        button {
+            onclick: move |_| sync_task.send(SyncAction::Username("Bob")),
+            "Click to sync your username to the server"
+        }
+    })
+}
+```
+
+## All New Features
+
+We've covered the major headlining features, but there were so many more!
+
+- A new router @autarch
+- Fermi for global state management
+- Translation of docs and Readme into Chinese @mrxiaozhuox
+- 2.5x speedup by using JS-based DOM manipulation (3x faster than React)
+- Beautiful documentation overhaul
+- InlineProps macro allows definition of props within a component's function arguments
+- Improved dev server, hot reloading for desktop and web apps [@mrxiaozhuox](https://github.com/mrxiaozhuox)
+- Templates: desktop, web, web/hydration, Axum + SSR, and more [@mrxiaozhuox](https://github.com/mrxiaozhuox)
+- Web apps ship with console_error_panic_hook enabled, so you always get tracebacks
+- Enhanced Hydration and server-side-rendering (recovery, validation)
+- Optional fields for component properties
+- Introduction of the `EventHandler` type
+- Improved use_state hook to be closer to react
+- Improved use_ref hook to be easier to use in async contexts
+- New use_coroutine hook for carefully controlling long-running async tasks
+- Prevent Default attribute
+- Provide Default Context allows injection of global contexts to the top of the app
+- push_future now has a spawn counterpart to be more consistent with rust
+- Add gap and gap_row attributes [@FruitieX](https://github.com/FruitieX)
+- File Drag n Drop support for Desktop
+- Custom handler support for desktop
+- Forms now collect all their values in oninput/onsubmit
+- Async tasks now are dropped when components unmount
+- Right-click menus are now disabled by default
+
+## Fixes
+- Windows support improved across the board
+- Linux support improved across the board
+- Bug in Calculator example
+- Improved example running support
+
+A ton more! Dioxus is now much more stable than it was at release!
+
+## Breaking Changes and Migrations
+
+- UseState is not `Copy` - but now supports Clone for use in async. `for_async` has been removed
+- UseFuture and UseEffect now take dependency tuples
+- UseCoroutine is now exposed via the context API and takes a receiver
+- Async tasks are canceled when components are dropped
+- The ContextAPI no longer uses RC to share state - anything that is `Clone` can be shared
+
+## Community Additions
+- [Styled Components macro](https://github.com/Zomatree/Revolt-Client/blob/master/src/utils.rs#14-27) [@Zomatree](https://github.com/Zomatree)
+- [Dioxus-Websocket hook](https://github.com/FruitieX/dioxus-websocket-hooks) [@FruitieX](https://github.com/FruitieX)
+- [Home automation server app](https://github.com/FruitieX/homectl) [@FruitieX](https://github.com/FruitieX)
+- [Video Recording app](https://github.com/rustkid/recorder)
+- [Music streaming app](https://github.com/autarch/Crumb/tree/master/web-frontend) [@autarch](https://github.com/autarch)
+- [NixOS dependency installation](https://gist.github.com/FruitieX/73afe3eb15da45e0e05d5c9cf5d318fc) [@FruitieX](https://github.com/FruitieX)
+- [Vercel Deploy Template](https://github.com/lucifer1004/dioxus-vercel-demo) [@lucifer1004](https://github.com/lucifer1004)
+- [Render Katex in Dioxus](https://github.com/oovm/katex-wasm)
+- [Render PrismJS in Dioxus](https://github.com/oovm/prism-wasm)
+- [Compile-time correct TailwindCSS](https://github.com/houseabsolute/tailwindcss-to-rust)
+- [Autogenerate tailwind CSS](https://github.com/oovm/tailwind-rs)
+- [Heroicons library](https://github.com/houseabsolute/dioxus-heroicons)
+- [RSX -> HTML translator app](https://dioxus-convert.netlify.app)
+- [Toast Support](https://github.com/mrxiaozhuox/dioxus-toast)
+- New Examples: forms, routers, linking, tui, and more!
+
+## Looking Forward
+
+Dioxus is still under rapid, active development. We'd love for you to get involved! For the next release, we're looking to add:
+
+- Native WGPU renderer support
+- A query library like react-query
+- Multiwindow desktop app support
+- Full LiveView integrations for Axum, Warp, and Actix
+- A builder pattern for elements (no need for rsx!)
+- Autoformatting of rsx! code (like cargo fmt)
+- Improvements to the VSCode Extension
+
+If you're interested in building an app with Dioxus, make sure to check us out on:
+
+- [Github](http://github.com/dioxusLabs/dioxus)
+- [Reddit](http://reddit.com/r/dioxus/)
+- [Discord](https://discord.gg/XgGxMSkvUM)
+- [Twitter](http://twitter.com/dioxuslabs)
+
+

+ 408 - 0
docs/posts/release.md

@@ -0,0 +1,408 @@
+# Introducing Dioxus v0.1 ✨
+
+> Jan 3, 2022
+
+> [@jkelleyrtp](https://github.com/jkelleyrtp), thanks [@alexkirsz](https://github.com/alexkirsz)
+
+After many months of work, we're very excited to release the first version of Dioxus!
+
+Dioxus is a new library for building interactive user interfaces (GUI) with Rust. It is built around a Virtual DOM, making it portable for the web, desktop, server, mobile, and more. 
+
+Dioxus has the following design goals:
+
+- **Familiar**: Offer a React-like mental model and API surface
+- **Robust**: Avoid runtime bugs by moving rules and error handling into the type system
+- **Performant**: Scale to the largest apps and the largest teams
+- **Productive**: Comprehensive inline documentation, fast recompiles, and deeply integrated tooling
+- **Extensible**: Reusable hooks and components that work on every platform
+
+Dioxus is designed to be familiar for developers already comfortable with React paradigms. Our goal is to ensure a smooth transition from TypeScript/React without having to learn any major new concepts.
+
+To give you an idea of what Dioxus looks like, here's a simple counter app:
+
+```rust
+use dioxus::prelude::*;
+
+fn main() {
+	dioxus::desktop::launch(app)
+}
+
+fn app(cx: Scope) -> Element {
+    let mut count = use_state(&cx, || 0);
+
+    cx.render(rsx! {
+        h1 { "Count: {count}" }
+        button { onclick: move |_| count += 1, "+" }
+        button { onclick: move |_| count -= 1, "-" }
+    })
+}
+```
+
+This simple counter is a complete desktop application, running at native speeds on a native thread. Dioxus automatically shuttles all events from the WebView runtime into the application code. In our app, we can interact natively with system APIs, run multi-threaded code, and do anything a regular native Rust application might do. Running `cargo build --release` will compile a portable binary that looks and feels the same on Windows, macOS, and Linux. We can then use `cargo-bundle` to bundle our binary into a native `.app`/`.exe`/`.deb`.
+
+Dioxus supports many of the same features React does including:
+
+- Server-side-rendering, pre-rendering, and hydration
+- Mobile, desktop, and web support
+- Suspense, fibers, coroutines, and error handling
+- Hooks, first-class state management, components
+- Fragments, conditional rendering, and custom elements
+
+However, some things are different in Dioxus:
+
+- Automatic memoization (opt-out rather than opt-in)
+- No effects - effectual code can only originate from actions or coroutines
+- Suspense is implemented as hooks - _not_ deeply ingrained within Dioxus Core
+- Async code is _explicit_ with a preference for _coroutines_ instead
+
+As a demo, here's our teaser example running on all our current supported platforms:
+
+![Teaser Example](/static/Untitled.png)
+
+This very site is built with Dioxus, and the source code is available [here](https://github.com/dioxuslabs/docsite).
+
+To get started with Dioxus, check out any of the "Getting Started" guides for your platform of choice, or check out the GitHub Repository for more details.
+
+- [Getting Started with Dioxus](https://dioxuslabs.com/guide)
+- [Getting Started with Web](https://dioxuslabs.com/reference/web)
+- [Getting Started with Desktop](https://dioxuslabs.com/reference/desktop)
+- [Getting Started with Mobile](https://dioxuslabs.com/reference/mobile)
+- [Getting Started with SSR](https://dioxuslabs.com/reference/ssr)
+
+## Show me some examples of what can be built!
+
+- [File explorer desktop app](https://github.com/dioxuslabs/example-projects)
+- [WiFi scanner desktop app](https://github.com/dioxuslabs/example-projects)
+- [Dog CEO API Search](https://github.com/dioxuslabs/example-projects)
+- [TodoMVC Mobile App](https://github.com/dioxuslabs/example-projects)
+- [E-Commerce Liveview App](https://github.com/dioxuslabs/example-projects)
+
+## Why should I use Rust and Dioxus for frontend?
+
+We believe that Rust's ability to write high-level and statically typed code should make it easier for frontend teams to take on even the most ambitious of projects. Rust projects can be refactored fearlessly: the powerful type system prevents an entire class of bugs at compile-time. No more `cannot read property of undefined` ever again! With Rust, all errors must be accounted for at compile time. You cannot ship an app that does not — in some way — handle its errors.
+
+### Difference from TypeScript/React:
+
+TypeScript is still fundamentally JavaScript. If you've written enough TypeScript, you might be bogged down with lots of configuration options, lack of proper support for "go-to-source," or incorrect ad-hoc typing. With Rust, strong types are built-in, saving tons of headache like `cannot read property of undefined`.
+
+By using Rust, we gain:
+
+- Strong types for every library
+- Immutability by default
+- A simple and intuitive module system
+- Integrated documentation (go to source actually goes to source instead of the `.d.ts` file)
+- Advanced pattern matching
+- Clean, efficient, composable iterators
+- Inline built-in unit/integration testing
+- High quality error handling
+- Flexible standard library and traits
+- Powerful macro system
+- Access to the [crates.io](https://crates.io) ecosystem
+
+Dioxus itself leverages this platform to provide the following guarantees:
+
+- Correct use of immutable data structures
+- Guaranteed handling of errors and null-values in components
+- Native performance on mobile
+- Direct access to system IO
+
+And much more. Dioxus makes Rust apps just as fast to write as React apps, but affords more robustness, giving your frontend team greater confidence in making big changes in shorter timespans.
+
+Semantically, TypeScript-React and Rust-Dioxus are very similar. In TypeScript, we would declare a simple component as:
+
+```tsx
+type CardProps = {
+  title: string,
+  paragraph: string,
+};
+
+const Card: FunctionComponent<CardProps> = (props) => {
+  let [count, set_count] = use_state(0);
+  return (
+    <aside>
+      <h2>{props.title}</h2>
+      <p> {props.paragraph} </p>
+	  <button onclick={() => set_count(count + 1)}> Count {count} </button>
+    </aside>
+  );
+};
+```
+
+In Dioxus, we would define the same component in a similar fashion:
+
+```rust
+#[derive(Props, PartialEq)]
+struct CardProps {
+	title: String,
+	paragraph: String
+}
+
+static Card: Component<CardProps> = |cx| {
+	let mut count = use_state(&cx, || 0);
+	cx.render(rsx!(
+		aside {
+			h2 { "{cx.props.title}" }
+			p { "{cx.props.paragraph}" }
+			button { onclick: move |_| count+=1, "Count: {count}" }
+		}
+	))
+};
+```
+
+However, we recognize that not every project needs Rust - many are fine with JavaScript! We also acknowledge that Rust/Wasm/Dioxus does not fix "everything that is wrong with frontend development." There are always going to be new patterns, frameworks, and languages that solve these problems better than Rust and Dioxus.
+
+As a general rule of thumb, Dioxus is for you if:
+
+- your app will become very large
+- you need to share code across many platforms
+- you want a fast way to build for desktop
+- you want to avoid electron or need direct access to hardware
+- you're tired of JavaScript tooling
+
+Today, to publish a Dioxus app, you don't need NPM/WebPack/Parcel/etc. Dioxus simply builds with cargo, and for web builds, Dioxus happily works with the popular [trunk](http://trunkrs.dev) project.
+
+## Show me more
+
+Here, we'll dive into some features of Dioxus and why it's so fun to use. The [guide](https://dioxuslabs.com/guide/) serves as a deeper and more comprehensive look at what Dioxus can do.
+
+## Building a new project is simple
+
+To start a new project, all you need is Cargo, which comes with Rust. For a simple desktop app, all we'll need is the `dioxus` crate with the appropriate `desktop` feature. We start by initializing a new binary crate:
+
+```shell
+$ cargo init dioxus_example
+$ cd dioxus_example
+```
+
+We then add a dependency on Dioxus to the `Cargo.toml` file, with the "desktop" feature enabled:
+
+```rust
+[dependencies]
+dioxus = { version = "*", features = ["desktop"] }
+```
+
+We can add our counter from above.
+
+```rust
+use dioxus::prelude::*;
+
+fn main() {
+	dioxus::desktop::launch(app)
+}
+
+fn app(cx: Scope) -> Element {
+    let mut count = use_state(&cx, || 0);
+
+    cx.render(rsx! {
+        h1 { "Count: {count}" }
+        button { onclick: move |_| count += 1, "+" }
+        button { onclick: move |_| count -= 1, "-" }
+    })
+}
+```
+
+And voilà! We can `cargo run` our app
+
+
+![Simple Counter Desktop App](/static/counter.png)
+
+## Support for JSX-style templating
+
+Dioxus ships with a templating macro called RSX, a spin on React's JSX. RSX is very similar to regular struct syntax for Rust so it integrates well with your IDE. If used with [Rust-Analyzer](https://github.com/rust-analyzer/rust-analyzer) (not tested anywhere else) RSX supports code-folding, block selection, bracket pair colorizing, autocompletion, symbol renaming — pretty much anything you would expect from writing regular struct-style code.
+
+```rust
+rsx! {
+	div { "Hello world" }
+	button {
+		onclick: move |_| log::info!("button pressed"),
+		"Press me"
+	}
+}
+```
+
+If macros aren't your style, you can always drop down to the factory API:
+
+```rust
+LazyNodes::new(|f| {
+	f.fragment([
+		f.element(div, [f.text("hello world")], [], None, None)
+		f.element(
+			button,
+			[f.text("Press Me")],
+			[on::click(move |_| log::info!("button pressed"))],
+			None,
+			None
+		)
+	])
+})
+```
+
+The `rsx!` macro generates idiomatic Rust code that uses the factory API — no different than what you'd write by hand yourself.
+
+To make it easier to work with RSX, we've built a small [VSCode extension](https://github.com/DioxusLabs/studio) with useful utilities. This extension provides a command that converts a selected block of HTML into RSX so you can easily reuse existing web templates. 
+
+## Dioxus prioritizes developer experience
+
+Many of the Rust UI frameworks are particularly difficult to work with. Even the ones branded as "ergonomic" are quite challenging to in comparison to TSX/JSX. With Dioxus, we've innovated on a number of Rust patterns to deliver a framework that is actually enjoyable to develop in.
+
+For example, many Rust frameworks require you to clone your data in for *every* closure and handler you use. This can get really clumsy for large apps.
+
+```rust
+div()
+	.children([
+		button().onclick(cloned!(name, date, age, description => move |evt| { /* */ })
+		button().onclick(cloned!(name, date, age, description => move |evt| { /* */ })
+		button().onclick(cloned!(name, date, age, description => move |evt| { /* */ })
+	])
+```
+
+Dioxus understands the lifetimes of data borrowed from `Scope`, so you can safely return any borrowed data without declaring explicit captures. Hook handles all implement `Copy` so they can be shared between listeners without any ceremony.
+
+
+```rust
+let name = use_state(&cx, || "asd");
+rsx! {
+	div {
+		button { onclick: move |_| name.set("abc") }
+		button { onclick: move |_| name.set("def") }
+		button { onclick: move |_| name.set("ghi") }
+	}
+}
+```
+
+Because we know the lifetime of your handlers, we can also expose this to children. No other Rust frameworks let us share borrowed state through the tree, forcing use of Rc/Arc everywhere. With Dioxus, all the Rc/Arc magic is tucked away in hooks, and just beautiful borrowed interfaces are exposed to your code. You don't need to know how Rc/RefCell work to build a competent Dioxus app.
+
+```rust
+fn app(cx: Scope) -> Element {
+	let name = use_state(&cx, || "asd");
+	cx.render(rsx!{
+		Button { name: name }
+	})
+}
+
+#[derive(Props)]
+struct ButtonProps<'a> {
+	name: UseState<'a, &'static str>
+}
+
+fn Button<'a>(cx: Scope<'a, Childprops<'a>>) -> Element {
+	cx.render(rsx!{
+		button {
+			onclick: move |_| cx.props.name.set("bob")
+		}
+	})
+}
+```
+
+There's *way* more to this story, but hopefully we've convinced you that Dioxus' DX somewhat approximates JSX/React.
+
+
+## Dioxus is perfected for the IDE
+
+Note: all IDE-related features have only been tested with [Rust-Analyzer](https://github.com/rust-analyzer/rust-analyzer). 
+
+Dioxus code operates pleasantly with your IDE. For starters, most elements are documented through the Rustdoc system. A quick summary of the MDN docs is always under your finger tips:
+
+![Elements have hover context](/static/ide_hover.png)
+
+Dioxus also wraps platform-specific events with a custom synthetic event system. This means events enjoy proper autocomplete and documentation, unlike [Yew](https://yew.rs/) which currently relies on [web-sys](https://crates.io/crates/web-sys) with incomplete IDE support:
+
+![Events are strongly typed](/static/ide_autocomplete.png)
+
+Even element attributes and event handlers have top-notch documentation!
+
+![Element attributes and listeners have hover context](/static/ide_listener.png)
+
+The `rsx!` macro also benefits from code folding, batch renaming, and block selection, making most basic code navigation and completion tasks a breeze.
+
+![Element blocks can be folded and renamed](/static/ide_selection.png)
+
+Furthermore, the `rsx!` macro itself is documented, so if you ever forget how to use a certain feature, the documentation remains close at hand:
+
+![The RSX documentation is provided on hover](/static/ide_rsx.png)
+
+We spent a ton of time on this and we hope you enjoy it!
+
+## Dioxus is extremely fast
+
+We take the performance of Dioxus seriously. Instead of resolving to "good enough," Dioxus is designed to push the limits of what a declarative React-like framework can achieve. Dioxus is designed with multi-tenancy in mind: a single machine should be able to run thousands of simultaneous low-latency LiveView apps without skipping a beat. To accomplish this goal we've implemented a large number of optimizations:
+
+- Usage of bump memory allocators and double-buffering
+- Compile-time hashing of templates
+- Automatic component memoization
+- Fiber-like scheduler
+- DOM Patch Batching
+
+Dioxus is humbly built off the work done by [Dodrio](https://github.com/fitzgen/dodrio), a now-archived research project by fitzgen exploring the use of bump allocators in UI frameworks.
+
+Dioxus is *substantially* more performant than many of the other Rust DOM-based UI libraries (Yew/Percy) and is *significantly* more performant than React - roughly competitive with InfernoJS. While not as performant as libraries like SolidJS/Sycamore, Dioxus imposes roughly a ~3% overhead over DOM patching, so it's *plenty* fast.
+
+## Works on Desktop and Mobile 
+We’ve mentioned before that Dioxus works practically anywhere that Rust does. When running natively as a desktop or mobile app, your Dioxus code will run on its own thread, not inside of a web runtime. This means you can access hardware, file system, and platform APIs directly without needing to go through a shim layer. In our examples, we feature a [file explorer app](https://github.com/DioxusLabs/example-projects/tree/master/file-explorer) and [WiFi scanner app](https://github.com/DioxusLabs/example-projects/tree/master/wifi-scanner) where platform access occurs inside an asynchronous multithreaded coroutine. This solves the problem faced by React Native and other cross-platform toolkits where JavaScript apps incur a massive performance penalty with substantial maintenance overhead associated with platform API shims.
+
+A desktop app:
+
+[![Example Dioxus desktop app](https://github.com/DioxusLabs/example-projects/raw/master/file-explorer/image.png)](https://github.com/DioxusLabs/example-projects/blob/master/file-explorer)
+
+A mobile app:
+
+[![Example Dioxus mobile app](https://github.com/DioxusLabs/example-projects/raw/master/ios_demo/assets/screenshot_smaller.jpeg)](https://github.com/DioxusLabs/example-projects/blob/master/ios_demo)
+
+However, be warned that mobile is currently considered very experimental and there will likely be quirks. Dioxus is leveraging the work done by the [Tauri](https://github.com/tauri-apps/tauri) team to enable mobile support, and mobile support isn't technically complete in Tauri yet.
+
+iOS should be supported out of the box, but Android support will take custom some boilerplate that hasn't been completely figured out. If you're interested in contributing to Dioxus, improving mobile support would be extremely helpful.
+
+### Did someone say TUI support?
+
+Yes, you can even build terminal user interfaces with Dioxus. Full support is still a work in progress, but the foundation is there.
+
+[![TUI Support](https://github.com/DioxusLabs/rink/raw/master/examples/example.png)](https://github.com/dioxusLabs/rink)
+
+### Things we didn't cover:
+
+There are a bunch of things we didn't talk about here. Check out the guide for more information, or peruse the examples and reference for more context.
+
+- Jank-free rendering with fiber scheduler
+- [Support for borrowed props]()
+- [Conditional rendering]()
+- [CSS/Styling/Inline style support]()
+- [Support for inline Context Providing/Consuming]()
+- [First-class global state management]()
+
+For a quick glance at party with React, check out the [Readme on Github](https://github.com/DioxusLabs/dioxus#parity-with-react).
+
+## What's on the roadmap?
+
+The world of Rust on the frontend is barely explored. Given the performance, ergonomics, and portability of Rust/Dioxus, we expect there to be a ton of different applications where having a React-like toolkit running natively can enable things previously considered impossible.
+
+In the coming weeks, our plan is to finish the remaining outstanding features where Dioxus is lacking in comparison to React:
+
+- Transition effects for Suspense
+- Micro-optimizations and better cross-platform/browser bug mitigations
+- Heuristics to guide the diffing algorithm
+- Better support for subtree memoization (signals, etc.)
+- More thorough documentation, fleshing out sore spots
+
+We also need some help in important crates currently missing:
+
+- First class cross-platform router (currently in progress)
+- An extension to DioxusStudio that enables lazy bundling of static assets
+- Animation library (see [React Spring](https://react-spring.io/), [Framer Motion](https://www.framer.com/motion/))
+- A [TUI renderer for Dioxus](https://github.com/dioxuslabs/rink) (see [Ink](https://github.com/vadimdemedes/ink))
+
+And finally, some bigger, forward-thinking projects that are too big for a one-person team:
+
+- Completely native renderer for the Dioxus Virtual DOM (see [Flutter](https://flutter.dev/))
+- Better support for LiveView
+- Code-splitting
+- 3D renderer (see [react-three-fiber](https://github.com/pmndrs/react-three-fiber))
+
+Stay tuned for our next article, which will go over some of the optimization techniques that went into making Dioxus blazing fast.
+
+## Community
+
+The future is bright for Rust frontends! If you'd like to get involved, we have a [Discord server](https://discord.gg/XgGxMSkvUM), [a subreddit](http://reddit.com/r/dioxus), and [GitHub discussion pages](https://github.com/DioxusLabs/dioxus/discussions). 
+
+Let us know what you build!
+
+Check out the original `/r/rust` thread here.

+ 6 - 5
docs/reference/src/SUMMARY.md

@@ -2,11 +2,12 @@
 
 - [Introduction](README.md)
 
-- [Web](web/index.md)
-- [Desktop](desktop/index.md)
-- [Mobile](mobile/index.md)
-- [SSR](ssr/index.md)
-- [TUI](tui/index.md)
+- [Platforms](platforms/index.md)
+  - [Web](platforms/web.md)
+  - [Server Side Rendering](platforms/ssr.md)
+  - [Desktop](platforms/desktop.md)
+  - [Mobile](platforms/mobile.md)
+  - [TUI](platforms/tui.md)
   
 - [Advanced Guides](guide/index.md)
   - [RSX in Depth](guide/rsx_in_depth.md)

+ 1 - 1
docs/reference/src/desktop/index.md → docs/reference/src/platforms/desktop.md

@@ -1,4 +1,4 @@
-# Desktop
+# Getting Started: Desktop
 
 One of Dioxus' killer features is the ability to quickly build a native desktop app that looks and feels the same across platforms. Apps built with Dioxus are typically <5mb in size and use existing system resources, so they won't hog extreme amounts of RAM or memory.
 

+ 10 - 0
docs/reference/src/platforms/index.md

@@ -0,0 +1,10 @@
+# Platforms
+
+Dioxus supports many different platforms. Below are a list of guides that walk you through setting up Dioxus for a specific platform.
+
+### Setup Guides
+- [Web](web.md)
+- [Server Side Rendering](ssr.md)
+- [Desktop](desktop.md)
+- [Mobile](mobile.md)
+- [TUI](tui.md)

+ 4 - 4
docs/reference/src/mobile/index.md → docs/reference/src/platforms/mobile.md

@@ -1,15 +1,15 @@
 # Getting started: mobile
 
 
-Dioxus is unique in that it actually supports mobile. However, support is very young and you might need to dip down into some of the primitives until better supported is ready.
+Dioxus is unique in that it actually supports mobile. However, support is very young and you might need to dip down into some of the primitives until better support is ready.
 
-Currently, only iOS is supported through us, however you *can* add android support by following the same instructions below, but using the `android` guide in `cargo-mobile`.
+Currently, only iOS is supported through us, however you *can* add android support by following the same instructions below by using the `android` guide in `cargo-mobile`.
 
 Also, Dioxus Desktop and Dioxus Mobile share the same codebase, and dioxus-mobile currently just re-exports dioxus-desktop.
 
 ## Getting Set up
 
-Getting set up with mobile can but quite challenging. The tooling here isn't great (yet) and might take some hacking around to get things working. macOS M1 is broadly unexplored and might not work for you.
+Getting set up with mobile can be quite challenging. The tooling here isn't great (yet) and might take some hacking around to get things working. macOS M1 is broadly unexplored and might not work for you.
 
 We're going to be using `cargo-mobile` to build for mobile. First, install it:
 
@@ -21,7 +21,7 @@ $ cargo install --git https://github.com/BrainiumLLC/cargo-mobile
 And then initialize your app for the right platform. Use the `winit` template for now. Right now, there's no "Dioxus" template in cargo-mobile.
 
 ```shell
-$ cargo moble init 
+$ cargo mobile init 
 ```
 
 We're going to completely clear out the `dependencies` it generates for us, swapping out `winit` with `dioxus-mobile`.

+ 12 - 12
docs/reference/src/ssr/index.md → docs/reference/src/platforms/ssr.md

@@ -2,11 +2,8 @@
 
 The Dioxus VirtualDom can be rendered to a string by traversing the Element Tree. This is implemented in the `ssr` crate where your Dioxus app can be directly rendered to HTML to be served by a web server.
 
-
-
 ## Setup
 
-
 If you just want to render `rsx!` or a VirtualDom to HTML, check out the API docs. It's pretty simple:
 
 ```rust
@@ -19,8 +16,7 @@ println!("{}", dioxus::ssr::render_vdom(&vdom));
 println!( "{}", dioxus::ssr::render_lazy(rsx! { h1 { "Hello, world!" } } );
 ```
 
-
-However, for this guide, we're going to show how to use Dioxus SSR with `Axum`. 
+However, for this guide, we're going to show how to use Dioxus SSR with `Axum`.
 
 Make sure you have Rust and Cargo installed, and then create a new project:
 
@@ -29,15 +25,16 @@ $ cargo new --bin demo
 $ cd app
 ```
 
-Add Dioxus with the `desktop` feature:
+Add Dioxus with the `ssr` feature:
 
 ```shell
 $ cargo add dioxus --features ssr
 ```
 
 Next, add all the Axum dependencies. This will be different if you're using a different Web Framework
+
 ```
-$ cargo add dioxus tokio --features full
+$ cargo add tokio --features full
 $ cargo add axum
 ```
 
@@ -45,12 +42,11 @@ Your dependencies should look roughly like this:
 
 ```toml
 [dependencies]
-axum = "0.4.3"
+axum = "0.4.5"
 dioxus = { version = "*", features = ["ssr"] }
 tokio = { version = "1.15.0", features = ["full"] }
 ```
 
-
 Now, setup your Axum app to respond on an endpoint.
 
 ```rust
@@ -63,7 +59,11 @@ async fn main() {
     println!("listening on http://{}", addr);
 
     axum::Server::bind(&addr)
-        .serve(Router::new().route("/", get(app_endpoint)))
+        .serve(
+            Router::new()
+                .route("/", get(app_endpoint))
+                .into_make_service(),
+        )
         .await
         .unwrap();
 }
@@ -88,14 +88,14 @@ async fn app_endpoint() -> Html<String> {
     }
     let mut app = VirtualDom::new(app);
     let _ = app.rebuild();
-    
+
     Html(dioxus::ssr::render_vdom(&app))
 }
 ```
 
 And that's it!
 
-> You might notice that you cannot hold the VirtualDom across an await point. Dioxus is currently not ThreadSafe, so it *must* remain on the thread it started. We are working on loosening this requirement.
+> You might notice that you cannot hold the VirtualDom across an await point. Dioxus is currently not ThreadSafe, so it _must_ remain on the thread it started. We are working on loosening this requirement.
 
 ## Future Steps
 

+ 100 - 0
docs/reference/src/platforms/tui.md

@@ -0,0 +1,100 @@
+# Getting Started: TUI
+
+TUI support is currently quite experimental. Even the project name will change. But, if you're willing to venture into the realm of the unknown, this guide will get you started.
+
+
+[TUI Support](https://github.com/DioxusLabs/rink/raw/master/examples/example.png)
+
+
+## Getting Set up
+
+
+To tinker with TUI support, start by making a new package and adding our TUI feature.
+
+```shell
+$ cargo new --bin demo
+$ cd demo
+$ cargo add dioxus --features tui
+```
+
+
+
+Then, edit your `main.rs` with the basic template. 
+
+```rust
+//  main
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::tui::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+
+            "Hello world!"
+        }
+    })
+}
+```
+
+To run our app:
+
+```shell
+$ cargo run
+```
+
+Press "ctrl-c" to close the app. To switch from "ctrl-c" to  just "q" to quit you can launch the app with a configuration to disable the default quit and use the root TuiContext to quit on your own.
+
+```rust
+//  main
+use dioxus::events::{KeyCode, KeyboardEvent};
+use dioxus::prelude::*;
+use dioxus::tui::TuiContext;
+
+fn main() {
+    dioxus::tui::launch_cfg(
+        app,
+        dioxus::tui::Config {
+            ctrl_c_quit: false,
+            // Some older terminals only support 16 colors or ANSI colors if your terminal is one of these change this to BaseColors or ANSI
+            rendering_mode: dioxus::tui::RenderingMode::Rgb,
+        },
+    );
+}
+
+fn app(cx: Scope) -> Element {
+    let tui_ctx: TuiContext = cx.consume_context().unwrap();
+
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+            onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.data.key_code {
+                tui_ctx.quit();
+            },
+
+            "Hello world!"
+        }
+    })
+}
+```
+
+## Notes
+
+- Our TUI package uses flexbox for layout
+- 1px is one character lineheight. Your regular CSS px does not translate.
+- If your app panics, your terminal is wrecked. This will be fixed eventually.
+
+## Future Steps
+
+Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't!

+ 2 - 2
docs/reference/src/web/index.md → docs/reference/src/platforms/web.md

@@ -1,4 +1,4 @@
-# Getting Started: Dioxus for Web
+# Getting Started: Web
 
 [*"Pack your things, we're going on an adventure!"*](https://trunkrs.dev)
 
@@ -77,7 +77,7 @@ trunk serve
 To build our app and publish it to Github:
 
 - Make sure Github Pages is set up for your repo
-- Build your app with `trunk build --release`
+- Build your app with `trunk build --release` (include `--public-url <repo-name>` to update asset prefixes if using a project site)
 - Move your generated HTML/CSS/JS/Wasm from `dist` into the folder configured for Github Pages
 - Add and commit with git
 - Push to Github

+ 0 - 67
docs/reference/src/tui/index.md

@@ -1,67 +0,0 @@
-# TUI
-
-TUI support is currently quite experimental. Even the project name will change. But, if you're willing to venture into the realm of the unknown, this guide will get you started.
-
-
-[TUI Support](https://github.com/DioxusLabs/rink/raw/master/examples/example.png)
-
-
-## Getting Set up
-
-
-To tinker with TUI support, start by making a new package and adding our TUI package from git.
-
-```shell
-$ cargo new --bin demo
-$ cd demo
-$ cargo add dioxus
-$ cargo add rink --git https://github.com/DioxusLabs/rink.git
-```
-
-
-
-Then, edit your `main.rs` with the basic template. 
-
-```rust
-//  main
-use dioxus::prelude::*;
-
-fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
-}
-
-fn app(cx: Scope) -> Element {
-    cx.render(rsx! {
-        div {
-            width: "100%",
-            height: "10px",
-            background_color: "red",
-            justify_content: "center",
-            align_items: "center",
-
-            "Hello world!"
-        }
-    })
-}
-```
-
-To run our app:
-
-```shell
-$ cargo run
-```
-
-Press "q" to close the app (yes, this is hardcoded, we are working on handlers to expose this in your code.)
-
-## Notes
-
-- Our TUI package uses flexbox for layout
-- 1px is one character lineheight. Your regular CSS px does not translate.
-- If your app panics, your terminal is wrecked. This will be fixed eventually.
-
-## Future Steps
-
-Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't!

+ 10 - 0
docs/router/src/README.md

@@ -0,0 +1,10 @@
+# Dioxus Router: Introduction
+Whether or not you're building a website, desktop app, or mobile app, organizing your app's views into "pages" can be an effective method for organization and maintainability. 
+
+Dioxus comes with a router built-in. To start utilizing Dioxus Router, enable the ``router`` feature in your ``Cargo.toml`` file.
+```toml
+[dependencies]
+dioxus = { version = "x.x.x", features = [.., "router"] }
+```
+
+In this book you'll find a short [guide](./guide/index.md) to get up to speed with Dioxus Router, as well as the router's [reference](./reference/index.md).

+ 9 - 1
docs/router/src/SUMMARY.md

@@ -1,3 +1,11 @@
 # Summary
 
-- [Chapter 1](./chapter_1.md)
+- [Introduction](./README.md)
+
+- [Guide](./guide/index.md)
+    - [Getting Started](./guide/getting-started.md)
+    - [Creating Our First Route](./guide/first-route.md)
+    - [Building a Nest](./guide/building-a-nest.md)
+    - [Redirection Perfection](./guide/redirection-perfection.md)
+- [Reference](./reference/index.md)
+    - [X]()

+ 0 - 3
docs/router/src/chapter_1.md

@@ -1,3 +0,0 @@
-# Chapter 1
-
-The Dioxus Router is very important!!

+ 201 - 0
docs/router/src/guide/building-a-nest.md

@@ -0,0 +1,201 @@
+# Building a Nest
+Not a bird's nest! A nest of routes!
+
+In this chapter we will begin to build the blog portion of our site which will include links, nested URLs, and URL parameters. We will also explore the use case of rendering components outside of routes.
+
+### Site Navigation
+Our site visitors won't know all the available pages and blogs on our site so we should provide a navigation bar for them.
+Let's create a new ``navbar`` component:
+```rs
+fn navbar(cx: Scope) -> Element {
+    cx.render(rsx! {
+        ul {
+            
+        }
+    })
+}
+```
+Our navbar will be a list of links going between our pages. We could always use an HTML anchor element but that would cause our page to unnecessarily reload. Instead we want to use the ``Link`` component provided by Dioxus Router. 
+
+The Link component is very similar to the Route component. It takes a path and an element. Add the Link component into your use statement and then add some links:
+```rs
+use dioxus::{
+    prelude::*,
+    router::{Route, Router, Link}, // UPDATED
+};
+
+...
+
+fn navbar(cx: Scope) -> Element {
+    cx.render(rsx! {
+        ul {
+            // NEW
+            Link { to: "/", "Home"}
+            br {}
+            Link { to: "/blog", "Blog"}
+        }
+    })
+}
+```
+>By default, the Link component only works for links within your application. To link to external sites, add the ``external: true`` property.
+>```rs 
+>Link { to: "https://github.com", external: true, "GitHub"}
+>```
+
+And finally, use the navbar component in your app component:
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            p { "-- Dioxus Blog --" }
+            self::navbar {} // NEW
+            Route { to: "/", self::homepage {}}
+            Route { to: "", self::page_not_found {}}
+        }
+    })
+}
+```
+Now you should see a list of links near the top of your page. Click on one and you should seamlessly travel between pages.
+
+##### WIP: Active Link Styling
+
+### URL Parameters and Nested Routes
+Many websites such as GitHub put parameters in their URL. For example, ``github.com/DioxusLabs`` utilizes the text after the domain to dynamically search and display content about an organization.
+
+We want to store our blogs in a database and load them as needed. This'll help prevent our app from being bloated therefor providing faster load times. We also want our users to be able to send people a link to a specific blog post.
+We could utilize a search page that loads a blog when clicked but then our users won't be able to share our blogs easily. This is where URL parameters come in. And finally, we also want our site to tell users they are on a blog page whenever the URL starts with``/blog``.
+
+The path to our blog will look like ``/blog/myBlogPage``. ``myBlogPage`` being the URL parameter.
+Dioxus Router uses the ``:name`` pattern so our route will look like ``/blog/:post``.  
+
+First, lets tell users when they are on a blog page. Add a new route in your app component.
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            p { "-- Dioxus Blog --" }
+            self::navbar {}
+            Route { to: "/", self::homepage {}}
+            // NEW
+            Route { 
+                to: "/blog",
+            }
+            Route { to: "", self::page_not_found {}}
+        }
+    })
+}
+```
+Routes can take components as parameters and we know that a route is a component. We nest routes by doing exactly what they are called, nesting them:
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            p { "-- Dioxus Blog --" }
+            self::navbar {}
+            Route { to: "/", self::homepage {}}
+            Route { 
+                to: "/blog",
+                Route { to: "/:post", "This is my blog post!" } // NEW
+            }
+            Route { to: "", self::page_not_found {}}
+        }
+    })
+}
+```
+Nesting our route like this isn't too helpful at first, but remember we want to tell users they are on a blog page. Let's move our ``p { "-- Dioxus Blog --" }`` inside of our ``/blog`` route.
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            self::navbar {}
+            Route { to: "/", self::homepage {}}
+            Route { 
+                to: "/blog",
+                p { "-- Dioxus Blog --" } // MOVED
+                Route { to: "/:post", "This is my blog post!" }
+            }
+            Route { to: "", self::page_not_found {}}
+        }
+    })
+}
+```
+Now our ``-- Dioxus Blog --`` text will be displayed whenever a user is on a path that starts with ``/blog``. Displaying content in a way that is page-agnostic is useful when building navigation menus, footers, and similar. 
+
+All that's left is to handle our URL parameter. We will begin by creating a ``get_blog_post`` function. In a real site, this function would call an API endpoint to get a blog post from the database. However, that is out of the scope of this guide so we will be utilizing static text.
+```rs
+fn get_blog_post(id: &str) -> String {
+    match id {
+        "foo" => "Welcome to the foo blog post!".to_string(),
+        "bar" => "This is the bar blog post!".to_string(),
+        id => format!("Blog post '{id}' does not exist!")
+    }
+}
+
+```
+Now that we have established our helper function, lets create a new ``blog_post`` component.
+```rs
+fn blog_post(cx: Scope) -> Element {
+    let blog_text = "";
+
+    cx.render(rsx! {
+        p { "{blog_text}" }
+    })
+}
+```
+All that's left is to extract the blog id from the URL and to call our helper function to get the blog text. To do this we need to utilize Dioxus Router's ``use_route`` hook.
+First start by adding ``use_route`` to your imports and then utilize the hook in your ``blog_post`` component.
+```rs
+use dioxus::{
+    prelude::*,
+    router::{use_route, Link, Route, Router}, // UPDATED
+};
+
+...
+
+fn blog_post(cx: Scope) -> Element {
+    let route = use_route(&cx); // NEW
+    let blog_text = "";
+
+    cx.render(rsx! {
+        p { "{blog_text}" }
+    })
+}
+```
+Dioxus Router provides built in methods to extract information from a route. We could utilize the ``segments``, ``nth_segment``, or ``last_segment`` method for our case but we'll use the ``segment`` method which extracts a specific URL parameter.
+The ``segment`` method also parses the parameter into any type for us. We'll use a match expression that handles a parsing error and on success, uses our helper function to grab the blog post.
+```rs
+fn blog_post(cx: Scope) -> Element {
+    let route = use_route(&cx);
+
+    // NEW
+    let blog_text = match route.segment::<String>("post").unwrap() {
+        Ok(val) => get_blog_post(&val),
+        Err(_) => "An unknown error occured".to_string(),
+    };
+
+    cx.render(rsx! {
+        p { "{blog_text}" }
+    })
+}
+```
+And finally add the ``blog_post`` component to your ``app`` component:
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            self::navbar {}
+            Route { to: "/", self::homepage {}}
+            Route {
+                to: "/blog",
+                p { "-- Dioxus Blog --" }
+                Route { to: "/:post", self::blog_post {} } // UPDATED
+            }
+            Route { to: "", self::page_not_found {}}
+        }
+    })
+}
+```
+That's it! If you head to ``/blog/foo`` you should see ``Welcome to the foo blog post!``.
+
+### Conclusion
+In this chapter we utilized Dioxus Router's Link, URL Parameter, and ``use_route`` functionality to build the blog portion of our application. In the next and final chapter, we will go over the ``Redirect`` component to redirect non-authorized users to another page.

+ 95 - 0
docs/router/src/guide/first-route.md

@@ -0,0 +1,95 @@
+# Creating Our First Route
+In this chapter, we will continue off of our new Dioxus project to create a homepage and start utilizing Dioxus Router!
+
+### Fundamentals
+Dioxus Router works based on a router and route component. If you've ever used [React Router](https://reactrouter.com/), you should feel at home with Dioxus Router.
+
+To get started, import the ``Router`` and ``Route`` components.
+```rs
+use dioxus::{
+    prelude::*,
+    router::{Route, Router}
+}
+```
+We also need an actual page to route to! Add a homepage component:
+```rs
+fn homepage(cx: Scope) -> Element {
+    cx.render(rsx! {
+        p { "Welcome to Dioxus Blog!" }
+    })
+}
+```
+
+### To Route or Not to Route
+We want to use Dioxus Router to seperate our application into different "pages". Dioxus Router will then determine which page to render based on the URL path.
+
+To start using Dioxus Router, we need to use the ``Router`` component.
+Replace the ``p { "Hello, wasm!" }`` in your ``app`` component with a Router component:
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {} // NEW
+    })
+}
+```
+Now we have established a router and we can create our first route. We will be creating a route for our homepage component we created earlier.
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            Route { to: "/", self::homepage {}} // NEW
+        }
+    })
+}
+```
+If you head to your application's browser tab, you should see the text ``Welcome to Dioxus Blog!`` when on the root URL (``http://localhost:8080/``). If you enter a different path for the URL, nothing should be displayed.
+
+This is because we told Dioxus Router to render the ``homepage`` component only when the URL path is ``/``. You can tell Dioxus Router to render any kind of component such as a ``div {}``.
+
+### What if a Route Doesn't Exist?
+In our example Dioxus Router doesn't render anything. If we wanted to, we could tell Dioxus Router to render a component all the time! Try it out:
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            p { "-- Dioxus Blog --" } // NEW
+            Route { to: "/", self::homepage {}}
+        }
+    })
+}
+```
+We will go into more detail about this in the next chapter.
+
+Many sites also have a "404" page for when a URL path leads to nowhere. Dioxus Router can do this too! Create a new ``page_not_found`` component.
+```rs
+fn page_not_found(cx: Scope) -> Element {
+    cx.render(rsx! {
+        p { "Oops! The page you are looking for doesn't exist!" }
+    })
+}
+```
+
+Now to tell Dioxus Router to render our new component when no route exists. Create a new route with a path of nothing:
+```rs
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            p { "-- Dioxus Blog --" }
+            Route { to: "/", self::homepage {}}
+            Route { to: "", self::page_not_found {}} // NEW
+        }
+    })
+}
+```
+Now when you go to a route that doesn't exist, you should see the page not found text and the text we told Dioxus Router to render all the time.
+```
+// localhost:8080/abc
+
+-- Dioxus Blog --
+Oops! The page you are looking for doesn't exist!
+```
+
+> Make sure you put your empty route at the bottom or else it'll override any routes below it!
+
+### Conclusion
+In this chapter we learned how to create a route and tell Dioxus Router what component to render when the URL path is equal to what we specified. We also created a 404 page to handle when a route doesn't exist. Next, we'll create the blog portion of our site. We will utilize nested routes and URL parameters.

+ 68 - 0
docs/router/src/guide/getting-started.md

@@ -0,0 +1,68 @@
+# Getting Started
+Before we start utilizing Dioxus Router, we need to initialize a Dioxus web application.
+
+#### Required Tools
+If you haven't already, make sure you install the [dioxus-cli](https://dioxuslabs.com/nightly/cli/) build tool and the rust ``wasm32-unknown-unknown`` target:
+```
+$ cargo install dioxus-cli
+    ...
+$ rustup target add wasm32-unkown-unknown
+    ...
+```
+
+### Creating the Project
+First, create a new cargo binary project:
+```
+cargo new --bin dioxus-blog
+```
+
+Next, we need to add dioxus with the web and router feature to our ``Cargo.toml`` file.
+```toml
+[package]
+name = "dioxus-blog"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+dioxus = { version = "0.1.8", features = ["web", "router"] }
+```
+
+Now we can start coding! Create an ``index.html`` file in the root of your project:
+```html
+<html>
+    <head>
+        <title>Dioxus Blog</title>
+    </head>
+    <body>
+        <div id="main"></div>
+    </body>
+</html>
+```
+You can add whatever you want to this file, just ensure that you have a ``div`` with the id of ``main`` in the root of your body element. This is essentially a handle to where Dioxus will render your components.
+
+Now move to ``src/main.rs`` and replace its contents with:
+```rs
+use dioxus::prelude::*;
+
+fn main() {
+    // Launch Dioxus web app
+    dioxus::web::launch(app);
+}
+
+// Our root component.
+fn app(cx: Scope) -> Element {
+    // Render "Hello, wasm!" to the screen.
+    cx.render(rsx! {
+        p { "Hello, wasm!"}
+    })
+}
+```
+
+Our project is now setup! To make sure everything is running correctly, in the root of your project run:
+```
+dioxus serve --platform web
+```
+Then head to [http://localhost:8080](http://localhost:8080) in your browser, and you should see ``Hello, wasm!`` on your screen.
+
+#### Conclusion
+We setup a new project with Dioxus and got everything running correctly. Next we'll create a small homepage and start our journey with Dioxus Router.

+ 14 - 0
docs/router/src/guide/index.md

@@ -0,0 +1,14 @@
+# Dioxus Router: Guide
+In this guide you'll learn to effectively use Dioxus Router whether you're building a small todo app or the next FAANG company. We will create a small website with a blog, homepage, and more!
+
+#### You'll learn how to
+- Create routes and render "pages".
+- Utilize nested routes, create a navigation bar, and render content for a set of routes.
+- Gather URL parameters to dynamically display content.
+- Redirect your visitors wherever you want.
+
+> Disclaimer
+>
+> This site will only display the features of Dioxus Router. It will not include any actual functionality. To keep things simple we will only be using a single file, this is not the recommended way of doing things with a real application.
+
+You can find the complete application [here](https://github.com/DogeDark/dioxus-router-example).

+ 51 - 0
docs/router/src/guide/redirection-perfection.md

@@ -0,0 +1,51 @@
+# Redirection Perfection
+You're well on your way to becoming a routing master!
+
+In this chapter we will cover utilizing the ``Redirect`` component so you can take Rickrolling to the next level. We will also provide some optional challenges at the end if you want to continue your practice with not only Dioxus Router but with Dioxus in general.
+
+### What Is This Redirect Thing?
+The ``Redirect`` component is simple! When Dioxus determines that it should be rendered, it will redirect your application visitor to wherever you want. 
+In this example, let's say that you added a secret page to your site but didn't have time to program in the permission system. As a quick fix you add a redirect.
+
+As always, let's first create a new component named ``secret_page``.
+```rs
+fn secret_page(cx: Scope) -> Element {
+    cx.render(rsx! {
+        p { "This page is not to be viewed!" }
+    })
+}
+```
+To redirect our visitors, all we have to do is render the ``Redirect`` component. The ``Redirect`` component is very similar to the ``Link`` component. The main difference is it doesn't display anything new.
+First import the ``Redirect`` component and then update your ``secret_page`` component:
+```rs
+use dioxus::{
+    prelude::*,
+    router::{use_route, Link, Redirect, Route, Router}, // UPDATED
+};
+
+...
+
+fn secret_page(cx: Scope) -> Element {
+    cx.render(rsx! {
+        p { "This page is not to be viewed!" }
+        Redirect { to: "/" } // NEW
+    })
+}
+```
+That's it! Now your users will be redirected away from the secret page.
+
+>Similar to the ``Link`` component, the ``Redirect`` component needs to be explicitly set to redirect to an external site. To link to external sites, add the ``external: true`` property.
+>```rs 
+>Redirect { to: "https://github.com", external: true}
+>```
+
+### Conclusion 
+Well done! You've completed the Dioxus Router guide book. You've built a small application and learned about the many things you can do with Dioxus Router. To continue your journey, you can find a list of challenges down below, or you can check out the [reference](../reference/index.md).
+
+### Challenges
+- Organize your components into seperate files for better maintainability.
+- Give your app some style if you haven't already.
+- Build an about page so your visitors know who you are.
+- Add a user system that uses URL parameters.
+- Create a simple admin system to create, delete, and edit blogs.
+- If you want to go to the max, hook up your application to a rest API and database.

+ 2 - 0
docs/router/src/reference/index.md

@@ -0,0 +1,2 @@
+# Dioxus Router: Reference
+This section includes a reference to Dioxus Router's API and functionality.

+ 10 - 8
examples/README.md

@@ -41,6 +41,8 @@ These examples are not necessarily meant to be run, but rather serve as a refere
 | [Anti-patterns](./antipatterns.rs)                  | A collection of discouraged patterns            | ✅      |
 | [Complete rsx reference](./rsx_usage.rs)            | A complete reference for all rsx! usage         | ✅      |
 | [Event Listeners](./listener.rs)                    | Attach closures to events on elements           | ✅      |
+| [Inline Props](./inlineprops.rs)                    | Using the `#[inline_props]` macro               | ✅      |
+| [Eval](./eval.rs)                                   | Evaluate dynamic JavaScript code                | ✅      |
 
 
 ## Show me some examples!
@@ -51,7 +53,7 @@ In our collection of examples, guides, and tutorials, we have:
 - The reference (a collection of examples with heavy documentation)
 - The general examples
 - The platform-specific examples (web, ssr, desktop, mobile, server)
-  
+
 Here's what a few common tasks look like in Dioxus:
 
 Nested components with children and internal state:
@@ -80,7 +82,7 @@ Controlled inputs:
 ```rust
 fn App(cx: Scope) -> Element {
   let value = use_state(&cx, String::new);
-  cx.render(rsx!( 
+  cx.render(rsx!(
     input {
       "type": "text",
       value: "{value}",
@@ -96,16 +98,16 @@ fn App(cx: Scope) -> Element {
   let list = (0..10).map(|i| {
     rsx!(li { key: "{i}", "Value: {i}" })
   });
-  
+
   let title = match list.len() {
     0 => rsx!("Not enough"),
     _ => rsx!("Plenty!"),
   };
 
   if should_show {
-    cx.render(rsx!( 
+    cx.render(rsx!(
       title,
-      ul { list } 
+      ul { list }
     ))
   } else {
     None
@@ -165,18 +167,18 @@ fn App(cx: Scope) -> Element {
       Route::Home => rsx!( Home {} ),
       Route::Post(id) => rsx!( Post { id: id })
     }
-  }))  
+  }))
 }
 ```
 
-Suspense 
+Suspense
 ```rust
 fn App(cx: Scope) -> Element {
   let doggo = use_suspense(cx,
     || async { reqwest::get("https://dog.ceo/api/breeds/image/random").await.unwrap().json::<Response>().await.unwrap() },
     |response| cx.render(rsx!( img { src: "{response.message}" }))
   );
-  
+
   cx.render(rsx!{
     div {
       "One doggo coming right up:",

+ 411 - 0
examples/all_css.rs

@@ -0,0 +1,411 @@
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+          align_content: "a",
+          align_items: "a",
+          align_self: "a",
+          alignment_adjust: "a",
+          alignment_baseline: "a",
+          all: "a",
+          alt: "a",
+          animation: "a",
+          animation_delay: "a",
+          animation_direction: "a",
+          animation_duration: "a",
+          animation_fill_mode: "a",
+          animation_iteration_count: "a",
+          animation_name: "a",
+          animation_play_state: "a",
+          animation_timing_function: "a",
+          azimuth: "a",
+          backface_visibility: "a",
+          background: "a",
+          background_attachment: "a",
+          background_clip: "a",
+          background_color: "a",
+          background_image: "a",
+          background_origin: "a",
+          background_position: "a",
+          background_repeat: "a",
+          background_size: "a",
+          background_blend_mode: "a",
+          baseline_shift: "a",
+          bleed: "a",
+          bookmark_label: "a",
+          bookmark_level: "a",
+          bookmark_state: "a",
+          border: "a",
+          border_color: "a",
+          border_style: "a",
+          border_width: "a",
+          border_bottom: "a",
+          border_bottom_color: "a",
+          border_bottom_style: "a",
+          border_bottom_width: "a",
+          border_left: "a",
+          border_left_color: "a",
+          border_left_style: "a",
+          border_left_width: "a",
+          border_right: "a",
+          border_right_color: "a",
+          border_right_style: "a",
+          border_right_width: "a",
+          border_top: "a",
+          border_top_color: "a",
+          border_top_style: "a",
+          border_top_width: "a",
+          border_collapse: "a",
+          border_image: "a",
+          border_image_outset: "a",
+          border_image_repeat: "a",
+          border_image_slice: "a",
+          border_image_source: "a",
+          border_image_width: "a",
+          border_radius: "a",
+          border_bottom_left_radius: "a",
+          border_bottom_right_radius: "a",
+          border_top_left_radius: "a",
+          border_top_right_radius: "a",
+          border_spacing: "a",
+          bottom: "a",
+          box_decoration_break: "a",
+          box_shadow: "a",
+          box_sizing: "a",
+          box_snap: "a",
+          break_after: "a",
+          break_before: "a",
+          break_inside: "a",
+          buffered_rendering: "a",
+          caption_side: "a",
+          clear: "a",
+          clear_side: "a",
+          clip: "a",
+          clip_path: "a",
+          clip_rule: "a",
+          color: "a",
+          color_adjust: "a",
+          color_correction: "a",
+          color_interpolation: "a",
+          color_interpolation_filters: "a",
+          color_profile: "a",
+          color_rendering: "a",
+          column_fill: "a",
+          column_gap: "a",
+          column_rule: "a",
+          column_rule_color: "a",
+          column_rule_style: "a",
+          column_rule_width: "a",
+          column_span: "a",
+          columns: "a",
+          column_count: "a",
+          column_width: "a",
+          contain: "a",
+          content: "a",
+          counter_increment: "a",
+          counter_reset: "a",
+          counter_set: "a",
+          cue: "a",
+          cue_after: "a",
+          cue_before: "a",
+          cursor: "a",
+          direction: "a",
+          display: "a",
+          display_inside: "a",
+          display_outside: "a",
+          display_extras: "a",
+          display_box: "a",
+          dominant_baseline: "a",
+          elevation: "a",
+          empty_cells: "a",
+          enable_background: "a",
+          fill: "a",
+          fill_opacity: "a",
+          fill_rule: "a",
+          filter: "a",
+          float: "a",
+          float_defer_column: "a",
+          float_defer_page: "a",
+          float_offset: "a",
+          float_wrap: "a",
+          flow_into: "a",
+          flow_from: "a",
+          flex: "a",
+          flex_basis: "a",
+          flex_grow: "a",
+          flex_shrink: "a",
+          flex_flow: "a",
+          flex_direction: "a",
+          flex_wrap: "a",
+          flood_color: "a",
+          flood_opacity: "a",
+          font: "a",
+          font_family: "a",
+          font_size: "a",
+          font_stretch: "a",
+          font_style: "a",
+          font_weight: "a",
+          font_feature_settings: "a",
+          font_kerning: "a",
+          font_language_override: "a",
+          font_size_adjust: "a",
+          font_synthesis: "a",
+          font_variant: "a",
+          font_variant_alternates: "a",
+          font_variant_caps: "a",
+          font_variant_east_asian: "a",
+          font_variant_ligatures: "a",
+          font_variant_numeric: "a",
+          font_variant_position: "a",
+          footnote_policy: "a",
+          glyph_orientation_horizontal: "a",
+          glyph_orientation_vertical: "a",
+          grid: "a",
+          grid_auto_flow: "a",
+          grid_auto_columns: "a",
+          grid_auto_rows: "a",
+          grid_template: "a",
+          grid_template_areas: "a",
+          grid_template_columns: "a",
+          grid_template_rows: "a",
+          grid_area: "a",
+          grid_column: "a",
+          grid_column_start: "a",
+          grid_column_end: "a",
+          grid_row: "a",
+          grid_row_start: "a",
+          grid_row_end: "a",
+          hanging_punctuation: "a",
+          height: "a",
+          hyphenate_character: "a",
+          hyphenate_limit_chars: "a",
+          hyphenate_limit_last: "a",
+          hyphenate_limit_lines: "a",
+          hyphenate_limit_zone: "a",
+          hyphens: "a",
+          icon: "a",
+          image_orientation: "a",
+          image_resolution: "a",
+          image_rendering: "a",
+          ime: "a",
+          ime_align: "a",
+          ime_mode: "a",
+          ime_offset: "a",
+          ime_width: "a",
+          initial_letters: "a",
+          inline_box_align: "a",
+          isolation: "a",
+          justify_content: "a",
+          justify_items: "a",
+          justify_self: "a",
+          kerning: "a",
+          left: "a",
+          letter_spacing: "a",
+          lighting_color: "a",
+          line_box_contain: "a",
+          line_break: "a",
+          line_grid: "a",
+          line_height: "a",
+          line_slack: "a",
+          line_snap: "a",
+          list_style: "a",
+          list_style_image: "a",
+          list_style_position: "a",
+          list_style_type: "a",
+          margin: "a",
+          margin_bottom: "a",
+          margin_left: "a",
+          margin_right: "a",
+          margin_top: "a",
+          marker: "a",
+          marker_end: "a",
+          marker_mid: "a",
+          marker_pattern: "a",
+          marker_segment: "a",
+          marker_start: "a",
+          marker_knockout_left: "a",
+          marker_knockout_right: "a",
+          marker_side: "a",
+          marks: "a",
+          marquee_direction: "a",
+          marquee_play_count: "a",
+          marquee_speed: "a",
+          marquee_style: "a",
+          mask: "a",
+          mask_image: "a",
+          mask_repeat: "a",
+          mask_position: "a",
+          mask_clip: "a",
+          mask_origin: "a",
+          mask_size: "a",
+          mask_box: "a",
+          mask_box_outset: "a",
+          mask_box_repeat: "a",
+          mask_box_slice: "a",
+          mask_box_source: "a",
+          mask_box_width: "a",
+          mask_type: "a",
+          max_height: "a",
+          max_lines: "a",
+          max_width: "a",
+          min_height: "a",
+          min_width: "a",
+          mix_blend_mode: "a",
+          nav_down: "a",
+          nav_index: "a",
+          nav_left: "a",
+          nav_right: "a",
+          nav_up: "a",
+          object_fit: "a",
+          object_position: "a",
+          offset_after: "a",
+          offset_before: "a",
+          offset_end: "a",
+          offset_start: "a",
+          opacity: "a",
+          order: "a",
+          orphans: "a",
+          outline: "a",
+          outline_color: "a",
+          outline_style: "a",
+          outline_width: "a",
+          outline_offset: "a",
+          overflow: "a",
+          overflow_x: "a",
+          overflow_y: "a",
+          overflow_style: "a",
+          overflow_wrap: "a",
+          padding: "a",
+          padding_bottom: "a",
+          padding_left: "a",
+          padding_right: "a",
+          padding_top: "a",
+          page: "a",
+          page_break_after: "a",
+          page_break_before: "a",
+          page_break_inside: "a",
+          paint_order: "a",
+          pause: "a",
+          pause_after: "a",
+          pause_before: "a",
+          perspective: "a",
+          perspective_origin: "a",
+          pitch: "a",
+          pitch_range: "a",
+          play_during: "a",
+          pointer_events: "a",
+          position: "a",
+          quotes: "a",
+          region_fragment: "a",
+          resize: "a",
+          rest: "a",
+          rest_after: "a",
+          rest_before: "a",
+          richness: "a",
+          right: "a",
+          ruby_align: "a",
+          ruby_merge: "a",
+          ruby_position: "a",
+          scroll_behavior: "a",
+          scroll_snap_coordinate: "a",
+          scroll_snap_destination: "a",
+          scroll_snap_points_x: "a",
+          scroll_snap_points_y: "a",
+          scroll_snap_type: "a",
+          shape_image_threshold: "a",
+          shape_inside: "a",
+          shape_margin: "a",
+          shape_outside: "a",
+          shape_padding: "a",
+          shape_rendering: "a",
+          size: "a",
+          speak: "a",
+          speak_as: "a",
+          speak_header: "a",
+          speak_numeral: "a",
+          speak_punctuation: "a",
+          speech_rate: "a",
+          stop_color: "a",
+          stop_opacity: "a",
+          stress: "a",
+          string_set: "a",
+          stroke: "a",
+          stroke_dasharray: "a",
+          stroke_dashoffset: "a",
+          stroke_linecap: "a",
+          stroke_linejoin: "a",
+          stroke_miterlimit: "a",
+          stroke_opacity: "a",
+          stroke_width: "a",
+          tab_size: "a",
+          table_layout: "a",
+          text_align: "a",
+          text_align_all: "a",
+          text_align_last: "a",
+          text_anchor: "a",
+          text_combine_upright: "a",
+          text_decoration: "a",
+          text_decoration_color: "a",
+          text_decoration_line: "a",
+          text_decoration_style: "a",
+          text_decoration_skip: "a",
+          text_emphasis: "a",
+          text_emphasis_color: "a",
+          text_emphasis_style: "a",
+          text_emphasis_position: "a",
+          text_emphasis_skip: "a",
+          text_height: "a",
+          text_indent: "a",
+          text_justify: "a",
+          text_orientation: "a",
+          text_overflow: "a",
+          text_rendering: "a",
+          text_shadow: "a",
+          text_size_adjust: "a",
+          text_space_collapse: "a",
+          text_spacing: "a",
+          text_transform: "a",
+          text_underline_position: "a",
+          text_wrap: "a",
+          top: "a",
+          touch_action: "a",
+          transform: "a",
+          transform_box: "a",
+          transform_origin: "a",
+          transform_style: "a",
+          transition: "a",
+          transition_delay: "a",
+          transition_duration: "a",
+          transition_property: "a",
+          unicode_bidi: "a",
+          vector_effect: "a",
+          vertical_align: "a",
+          visibility: "a",
+          voice_balance: "a",
+          voice_duration: "a",
+          voice_family: "a",
+          voice_pitch: "a",
+          voice_range: "a",
+          voice_rate: "a",
+          voice_stress: "a",
+          voice_volumn: "a",
+          volume: "a",
+          white_space: "a",
+          widows: "a",
+          width: "a",
+          will_change: "a",
+          word_break: "a",
+          word_spacing: "a",
+          word_wrap: "a",
+          wrap_flow: "a",
+          wrap_through: "a",
+          writing_mode: "a",
+          z_index: "a",
+        }
+    })
+}

+ 1 - 1
examples/borrowed.rs

@@ -42,7 +42,7 @@ struct C1Props<'a> {
 }
 
 fn Child1<'a>(cx: Scope<'a, C1Props<'a>>) -> Element {
-    let (left, right) = cx.props.text.split_once("=").unwrap();
+    let (left, right) = cx.props.text.split_once('=').unwrap();
 
     cx.render(rsx! {
         div {

+ 26 - 34
examples/calculator.rs

@@ -18,20 +18,16 @@ fn main() {
 }
 
 fn app(cx: Scope) -> Element {
-    let (display_value, set_display_value) = use_state(&cx, || String::from("0"));
+    let val = use_state(&cx, || String::from("0"));
 
     let input_digit = move |num: u8| {
-        if display_value == "0" {
-            set_display_value(String::new());
+        if val.get() == "0" {
+            val.set(String::new());
         }
-        set_display_value
-            .make_mut()
-            .push_str(num.to_string().as_str());
+        val.make_mut().push_str(num.to_string().as_str());
     };
 
-    let input_operator = move |key: &str| {
-        set_display_value.make_mut().push_str(key);
-    };
+    let input_operator = move |key: &str| val.make_mut().push_str(key);
 
     cx.render(rsx!(
         style { [include_str!("./assets/calculator.css")] }
@@ -54,34 +50,34 @@ fn app(cx: Scope) -> Element {
                         KeyCode::Num8 => input_digit(8),
                         KeyCode::Num9 => input_digit(9),
                         KeyCode::Backspace => {
-                            if !display_value.len() != 0 {
-                                set_display_value.make_mut().pop();
+                            if !val.len() != 0 {
+                                val.make_mut().pop();
                             }
                         }
                         _ => {}
                     },
-                    div { class: "calculator-display", [display_value.to_string()] }
+                    div { class: "calculator-display", [val.to_string()] }
                     div { class: "calculator-keypad",
                         div { class: "input-keys",
                             div { class: "function-keys",
                                 button {
                                     class: "calculator-key key-clear",
                                     onclick: move |_| {
-                                        set_display_value(String::new());
-                                        if !display_value.is_empty(){
-                                            set_display_value("0".into());
+                                        val.set(String::new());
+                                        if !val.is_empty(){
+                                            val.set("0".into());
                                         }
                                     },
-                                    [if display_value.is_empty() { "C" } else { "AC" }]
+                                    [if val.is_empty() { "C" } else { "AC" }]
                                 }
                                 button {
                                     class: "calculator-key key-sign",
                                     onclick: move |_| {
-                                        let temp = calc_val(display_value.clone());
+                                        let temp = calc_val(val.as_str());
                                         if temp > 0.0 {
-                                            set_display_value(format!("-{}", temp));
+                                            val.set(format!("-{}", temp));
                                         } else {
-                                            set_display_value(format!("{}", temp.abs()));
+                                            val.set(format!("{}", temp.abs()));
                                         }
                                     },
                                     "±"
@@ -89,8 +85,8 @@ fn app(cx: Scope) -> Element {
                                 button {
                                     class: "calculator-key key-percent",
                                     onclick: move |_| {
-                                        set_display_value(
-                                            format!("{}", calc_val(display_value.clone()) / 100.0)
+                                        val.set(
+                                            format!("{}", calc_val(val.as_str()) / 100.0)
                                         );
                                     },
                                     "%"
@@ -100,7 +96,7 @@ fn app(cx: Scope) -> Element {
                                 button { class: "calculator-key key-0", onclick: move |_| input_digit(0),
                                     "0"
                                 }
-                                button { class: "calculator-key key-dot", onclick: move |_| set_display_value.make_mut().push('.'),
+                                button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'),
                                     "●"
                                 }
                                 (1..10).map(|k| rsx!{
@@ -114,25 +110,21 @@ fn app(cx: Scope) -> Element {
                             }
                         }
                         div { class: "operator-keys",
-                            button { class: "calculator-key key-divide",
-                                onclick: move |_| input_operator("/"),
+                            button { class: "calculator-key key-divide", onclick: move |_| input_operator("/"),
                                 "÷"
                             }
-                            button { class: "calculator-key key-multiply",
-                                onclick: move |_| input_operator("*"),
+                            button { class: "calculator-key key-multiply", onclick: move |_| input_operator("*"),
                                 "×"
                             }
-                            button { class: "calculator-key key-subtract",
-                                onclick: move |_| input_operator("-"),
+                            button { class: "calculator-key key-subtract", onclick: move |_| input_operator("-"),
                                 "−"
                             }
-                            button { class: "calculator-key key-add",
-                                onclick: move |_| input_operator("+"),
+                            button { class: "calculator-key key-add", onclick: move |_| input_operator("+"),
                                 "+"
                             }
                             button { class: "calculator-key key-equals",
                                 onclick: move |_| {
-                                    set_display_value(format!("{}", calc_val(display_value.clone())));
+                                    val.set(format!("{}", calc_val(val.as_str())));
                                 },
                                 "="
                             }
@@ -145,8 +137,7 @@ fn app(cx: Scope) -> Element {
     ))
 }
 
-fn calc_val(val: String) -> f64 {
-    let mut result;
+fn calc_val(val: &str) -> f64 {
     let mut temp = String::new();
     let mut operation = "+".to_string();
 
@@ -169,7 +160,8 @@ fn calc_val(val: String) -> f64 {
         temp_value.push(c);
         start_index += 1;
     }
-    result = temp_value.parse::<f64>().unwrap();
+
+    let mut result = temp_value.parse::<f64>().unwrap();
 
     if start_index + 1 >= val.len() {
         return result;

+ 3 - 3
examples/core_reference/listener.rs

@@ -36,7 +36,7 @@ pub fn NonUpdatingEvents(cx: Scope) -> Element {
     cx.render(rsx! {
         div {
             button {
-                onclick: move |_| log::info!("Did not cause any updates!"),
+                onclick: move |_| log::trace!("Did not cause any updates!"),
                 "Click me to log!"
             }
         }
@@ -46,9 +46,9 @@ pub fn NonUpdatingEvents(cx: Scope) -> Element {
 pub fn DisablePropagation(cx: Scope) -> Element {
     cx.render(rsx! {
         div {
-            onclick: move |_| log::info!("event propagated to the div!")
+            onclick: move |_| log::trace!("event propagated to the div!")
             button {
-                onclick: move |evt| log::info!("Button will allow propagation"),
+                onclick: move |evt| log::trace!("Button will allow propagation"),
             }
         }
     })

+ 23 - 37
examples/crm.rs

@@ -6,11 +6,6 @@ use dioxus::prelude::*;
 fn main() {
     dioxus::desktop::launch(app);
 }
-enum Scene {
-    ClientsList,
-    NewClientForm,
-    Settings,
-}
 
 #[derive(Clone, Debug, Default)]
 pub struct Client {
@@ -21,10 +16,9 @@ pub struct Client {
 
 fn app(cx: Scope) -> Element {
     let clients = use_ref(&cx, || vec![] as Vec<Client>);
-    let (scene, set_scene) = use_state(&cx, || Scene::ClientsList);
-    let (firstname, set_firstname) = use_state(&cx, String::new);
-    let (lastname, set_lastname) = use_state(&cx, String::new);
-    let (description, set_description) = use_state(&cx, String::new);
+    let firstname = use_state(&cx, String::new);
+    let lastname = use_state(&cx, String::new);
+    let description = use_state(&cx, String::new);
 
     cx.render(rsx!(
         body {
@@ -35,11 +29,9 @@ fn app(cx: Scope) -> Element {
                 integrity: "sha384-Uu6IeWbM+gzNVXJcM9XV3SohHtmWE+3VGi496jvgX1jyvDTXfdK+rfZc8C1Aehk5",
                 crossorigin: "anonymous",
             }
-
             h1 {"Dioxus CRM Example"}
-
-            match scene {
-                Scene::ClientsList => rsx!(
+            Router {
+                Route { to: "/",
                     div { class: "crm",
                         h2 { margin_bottom: "10px", "List of clients" }
                         div { class: "clients", margin_left: "10px",
@@ -51,11 +43,11 @@ fn app(cx: Scope) -> Element {
                                 })
                             )
                         }
-                        button { class: "pure-button pure-button-primary", onclick: move |_| set_scene(Scene::NewClientForm), "Add New" }
-                        button { class: "pure-button", onclick: move |_| set_scene(Scene::Settings), "Settings" }
+                        Link { to: "/new", class: "pure-button pure-button-primary", "Add New" }
+                        Link { to: "/new", class: "pure-button", "Settings" }
                     }
-                ),
-                Scene::NewClientForm => rsx!(
+                }
+                Route { to: "/new",
                     div { class: "crm",
                         h2 { margin_bottom: "10px", "Add new client" }
                         form { class: "pure-form",
@@ -63,41 +55,39 @@ fn app(cx: Scope) -> Element {
                                 class: "new-client firstname",
                                 placeholder: "First name",
                                 value: "{firstname}",
-                                oninput: move |e| set_firstname(e.value.clone())
+                                oninput: move |e| firstname.set(e.value.clone())
                             }
                             input {
                                 class: "new-client lastname",
                                 placeholder: "Last name",
                                 value: "{lastname}",
-                                oninput: move |e| set_lastname(e.value.clone())
+                                oninput: move |e| lastname.set(e.value.clone())
                             }
                             textarea {
                                 class: "new-client description",
                                 placeholder: "Description",
                                 value: "{description}",
-                                oninput: move |e| set_description(e.value.clone())
+                                oninput: move |e| description.set(e.value.clone())
                             }
                         }
                         button {
                             class: "pure-button pure-button-primary",
                             onclick: move |_| {
                                 clients.write().push(Client {
-                                    description: (*description).clone(),
-                                    first_name: (*firstname).clone(),
-                                    last_name: (*lastname).clone(),
+                                    description: description.to_string(),
+                                    first_name: firstname.to_string(),
+                                    last_name: lastname.to_string(),
                                 });
-                                set_description(String::new());
-                                set_firstname(String::new());
-                                set_lastname(String::new());
+                                description.set(String::new());
+                                firstname.set(String::new());
+                                lastname.set(String::new());
                             },
                             "Add New"
                         }
-                        button { class: "pure-button", onclick: move |_| set_scene(Scene::ClientsList),
-                            "Go Back"
-                        }
+                        Link { to: "/", class: "pure-button", "Go Back" }
                     }
-                ),
-                Scene::Settings => rsx!(
+                }
+                Route { to: "/settings",
                     div {
                         h2 { margin_bottom: "10px", "Settings" }
                         button {
@@ -106,13 +96,9 @@ fn app(cx: Scope) -> Element {
                             onclick: move |_| clients.write().clear(),
                             "Remove all clients"
                         }
-                        button {
-                            class: "pure-button pure-button-primary",
-                            onclick: move |_| set_scene(Scene::ClientsList),
-                            "Go Back"
-                        }
+                        Link { to: "/", class: "pure-button pure-button-primary", "Go Back" }
                     }
-                )
+                }
             }
         }
     ))

+ 37 - 0
examples/custom_html.rs

@@ -0,0 +1,37 @@
+//! This example shows how to use a custom index.html and custom <HEAD> extensions
+//! to add things like stylesheets, scripts, and third-party JS libraries.
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch_cfg(app, |c| {
+        c.with_custom_head("<style>body { background-color: red; }</style>".into())
+    });
+
+    dioxus::desktop::launch_cfg(app, |c| {
+        c.with_custom_index(
+            r#"
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Dioxus app</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <style>body { background-color: blue; }</style>
+  </head>
+  <body>
+    <div id="main"></div>
+  </body>
+</html>
+        "#
+            .into(),
+        )
+    });
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            h1 {"hello world!"}
+        }
+    })
+}

+ 5 - 3
examples/disabled.rs

@@ -5,13 +5,15 @@ fn main() {
 }
 
 fn app(cx: Scope) -> Element {
-    let (disabled, set_disabled) = use_state(&cx, || false);
+    let disabled = use_state(&cx, || false);
 
     cx.render(rsx! {
         div {
             button {
-                onclick: move |_| set_disabled(!disabled),
-                "click to " [if *disabled {"enable"} else {"disable"} ] " the lower button"
+                onclick: move |_| disabled.set(!disabled),
+                "click to "
+                [if disabled == true {"enable"} else {"disable"}]
+                " the lower button"
             }
 
             button {

+ 21 - 30
examples/dog_app.rs

@@ -16,7 +16,9 @@ struct ListBreeds {
 }
 
 fn app(cx: Scope) -> Element {
-    let breeds = use_future(&cx, || async move {
+    let breed = use_state(&cx, || None);
+
+    let breeds = use_future(&cx, (), |_| async move {
         reqwest::get("https://dog.ceo/api/breeds/list/all")
             .await
             .unwrap()
@@ -24,26 +26,23 @@ fn app(cx: Scope) -> Element {
             .await
     });
 
-    let (breed, set_breed) = use_state(&cx, || None);
-
     match breeds.value() {
         Some(Ok(breeds)) => cx.render(rsx! {
             div {
-                h1 {"Select a dog breed!"}
-
+                h1 { "Select a dog breed!" }
                 div { display: "flex",
                     ul { flex: "50%",
-                        breeds.message.keys().map(|breed| rsx!(
+                        breeds.message.keys().map(|cur_breed| rsx!(
                             li {
                                 button {
-                                    onclick: move |_| set_breed(Some(breed.clone())),
-                                    "{breed}"
+                                    onclick: move |_| breed.set(Some(cur_breed.clone())),
+                                    "{cur_breed}"
                                 }
                             }
                         ))
                     }
                     div { flex: "50%",
-                        match breed {
+                        match breed.get() {
                             Some(breed) => rsx!( Breed { breed: breed.clone() } ),
                             None => rsx!("No Breed selected"),
                         }
@@ -51,34 +50,26 @@ fn app(cx: Scope) -> Element {
                 }
             }
         }),
-        Some(Err(_e)) => cx.render(rsx! {
-            div { "Error fetching breeds" }
-        }),
-        None => cx.render(rsx! {
-            div { "Loading dogs..." }
-        }),
+        Some(Err(_e)) => cx.render(rsx! { div { "Error fetching breeds" } }),
+        None => cx.render(rsx! { div { "Loading dogs..." } }),
     }
 }
 
+#[derive(serde::Deserialize, Debug)]
+struct DogApi {
+    message: String,
+}
+
 #[inline_props]
 fn Breed(cx: Scope, breed: String) -> Element {
-    #[derive(serde::Deserialize, Debug)]
-    struct DogApi {
-        message: String,
-    }
-
-    let endpoint = format!("https://dog.ceo/api/breed/{}/images/random", breed);
-
-    let fut = use_future(&cx, || async move {
-        reqwest::get(endpoint).await.unwrap().json::<DogApi>().await
+    let fut = use_future(&cx, (breed,), |(breed,)| async move {
+        reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
+            .await
+            .unwrap()
+            .json::<DogApi>()
+            .await
     });
 
-    let (name, set_name) = use_state(&cx, || breed.clone());
-    if name != breed {
-        set_name(breed.clone());
-        fut.restart();
-    }
-
     cx.render(match fut.value() {
         Some(Ok(resp)) => rsx! {
             button {

+ 22 - 0
examples/error_handle.rs

@@ -0,0 +1,22 @@
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    let val = use_state(&cx, || "0.0001");
+
+    let num = match val.parse::<f32>() {
+        Err(_) => return cx.render(rsx!("Parsing failed")),
+        Ok(num) => num,
+    };
+
+    cx.render(rsx! {
+        h1 { "The parsed value is {num}" }
+        button {
+            onclick: move |_| val.set("invalid"),
+            "Set an invalid number"
+        }
+    })
+}

+ 25 - 0
examples/eval.rs

@@ -0,0 +1,25 @@
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    let script = use_state(&cx, String::new);
+    let eval = use_eval(&cx);
+
+    cx.render(rsx! {
+        div {
+            input {
+                placeholder: "Enter an expression",
+                value: "{script}",
+                oninput: move |e| script.set(e.value.clone()),
+            }
+            button {
+                onclick: move |_| eval(script),
+
+                "Execute"
+            }
+        }
+    })
+}

+ 26 - 0
examples/events.rs

@@ -0,0 +1,26 @@
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div {
+            button {
+                ondblclick: move |_| {
+                    //
+                    println!("double clicked!");
+                },
+                "Click me!"
+            }
+            input {
+                 onfocusin: move |_| {
+                    //
+                    println!("blurred!");
+                },
+                "onblur": "console.log('blurred!')"
+            }
+        }
+    })
+}

+ 29 - 0
examples/fermi.rs

@@ -0,0 +1,29 @@
+#![allow(non_snake_case)]
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app)
+}
+
+static NAME: Atom<String> = |_| "world".to_string();
+
+fn app(cx: Scope) -> Element {
+    let name = use_read(&cx, NAME);
+
+    cx.render(rsx! {
+        div { "hello {name}!" }
+        Child {}
+    })
+}
+
+fn Child(cx: Scope) -> Element {
+    let set_name = use_set(&cx, NAME);
+
+    cx.render(rsx! {
+        button {
+            onclick: move |_| set_name("dioxus".to_string()),
+            "reset name"
+        }
+    })
+}

+ 1 - 1
examples/file_explorer.rs

@@ -28,7 +28,7 @@ fn app(cx: Scope) -> Element {
         }
         main {
             files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
-                let path_end = path.split('/').last().unwrap_or_else(|| path.as_str());
+                let path_end = path.split('/').last().unwrap_or(path.as_str());
                 let icon_type = if path_end.contains('.') {
                     "description"
                 } else {

+ 1 - 1
examples/filedragdrop.rs

@@ -12,7 +12,7 @@ fn main() {
 fn app(cx: Scope) -> Element {
     cx.render(rsx!(
         div {
-            h1 { "drag an file here" }
+            h1 { "drag a file here and check your console" }
         }
     ))
 }

+ 37 - 0
examples/flat_router.rs

@@ -0,0 +1,37 @@
+use dioxus::desktop::tao::dpi::LogicalSize;
+use dioxus::prelude::*;
+
+fn main() {
+    env_logger::init();
+
+    dioxus::desktop::launch_cfg(app, |c| {
+        c.with_window(|c| {
+            c.with_title("Spinsense Client")
+                .with_inner_size(LogicalSize::new(600, 1000))
+                .with_resizable(false)
+        })
+    })
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        Router {
+            Route { to: "/", "Home" }
+            Route { to: "/games", "Games" }
+            Route { to: "/play", "Play" }
+            Route { to: "/settings", "Settings" }
+
+            p {
+                "----"
+            }
+            nav {
+                ul {
+                    Link { to: "/", li { "Home" } }
+                    Link { to: "/games", li { "Games" } }
+                    Link { to: "/play", li { "Play" } }
+                    Link { to: "/settings", li { "Settings" } }
+                }
+            }
+        }
+    })
+}

+ 13 - 9
examples/form.rs

@@ -11,15 +11,19 @@ fn main() {
 
 fn app(cx: Scope) -> Element {
     cx.render(rsx! {
-        div {
-            h1 { "Form" }
-            form {
-                onsubmit: move |ev| println!("Submitted {:?}", ev.values),
-                oninput: move |ev| println!("Input {:?}", ev.values),
-                input { r#type: "text", name: "username" }
-                input { r#type: "text", name: "full-name" }
-                input { r#type: "password", name: "password" }
-                button { "Submit the form" }
+        Router {
+            div {
+                h1 { "Form" }
+                form {
+                    onsubmit: move |ev| println!("Submitted {:?}", ev.values),
+                    oninput: move |ev| println!("Input {:?}", ev.values),
+                    input { r#type: "text", name: "username" }
+                    input { r#type: "text", name: "full-name" }
+                    input { r#type: "password", name: "password" }
+                    input { r#type: "radio", name: "color", value: "red" }
+                    input { r#type: "radio", name: "color", value: "blue" }
+                    button { r#type: "submit", value: "Submit", "Submit the form" }
+                }
             }
         }
     })

+ 2 - 2
examples/framework_benchmark.rs

@@ -33,7 +33,7 @@ impl Label {
 
 fn app(cx: Scope) -> Element {
     let items = use_ref(&cx, Vec::new);
-    let (selected, set_selected) = use_state(&cx, || None);
+    let selected = use_state(&cx, || None);
 
     cx.render(rsx! {
         div { class: "container",
@@ -71,7 +71,7 @@ fn app(cx: Scope) -> Element {
                         rsx!(tr { class: "{is_in_danger}",
                             td { class:"col-md-1" }
                             td { class:"col-md-1", "{item.key}" }
-                            td { class:"col-md-1", onclick: move |_| set_selected(Some(id)),
+                            td { class:"col-md-1", onclick: move |_| selected.set(Some(id)),
                                 a { class: "lbl", item.labels }
                             }
                             td { class: "col-md-1",

+ 28 - 0
examples/heavy_compute.rs

@@ -0,0 +1,28 @@
+//! This example shows that you can place heavy work on the main thread, and then
+//!
+//! You *should* be using `tokio::spawn_blocking` instead.
+//!
+//! Your app runs in an async runtime (Tokio), so you should avoid blocking
+//! the rendering of the VirtualDom.
+//!
+//!
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    // This is discouraged
+    std::thread::sleep(std::time::Duration::from_millis(2_000));
+
+    // This is suggested
+    tokio::task::spawn_blocking(move || {
+        std::thread::sleep(std::time::Duration::from_millis(2_000));
+    });
+
+    cx.render(rsx! {
+        div { "Hello, world!" }
+    })
+}

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels