소스 검색

Clean up a number of examples

Jonathan Kelley 1 년 전
부모
커밋
6134a2ce24

+ 10 - 10
examples/calculator.rs

@@ -26,15 +26,15 @@ fn app() -> Element {
             val.set(String::new());
         }
 
-        val.make_mut().push_str(num.to_string().as_str());
+        val.write().push_str(num.to_string().as_str());
     };
 
-    let input_operator = move |key: &str| val.make_mut().push_str(key);
+    let input_operator = move |key: &str| val.write().push_str(key);
 
     let handle_key_down_event = move |evt: KeyboardEvent| match evt.key() {
         Key::Backspace => {
-            if !val.len() != 0 {
-                val.make_mut().pop();
+            if !val().is_empty() {
+                val.write().pop();
             }
         }
         Key::Character(character) => match character.as_str() {
@@ -72,16 +72,16 @@ fn app() -> Element {
                                     class: "calculator-key key-clear",
                                     onclick: move |_| {
                                         val.set(String::new());
-                                        if !val.is_empty(){
+                                        if !val().is_empty(){
                                             val.set("0".into());
                                         }
                                     },
-                                    if val.is_empty() { "C" } else { "AC" }
+                                    if val().is_empty() { "C" } else { "AC" }
                                 }
                                 button {
                                     class: "calculator-key key-sign",
                                     onclick: move |_| {
-                                        let temp = calc_val(val.as_str());
+                                        let temp = calc_val(val().as_str());
                                         if temp > 0.0 {
                                             val.set(format!("-{temp}"));
                                         } else {
@@ -94,7 +94,7 @@ fn app() -> Element {
                                     class: "calculator-key key-percent",
                                     onclick: move |_| {
                                         val.set(
-                                            format!("{}", calc_val(val.as_str()) / 100.0)
+                                            format!("{}", calc_val(val().as_str()) / 100.0)
                                         );
                                     },
                                     "%"
@@ -102,7 +102,7 @@ fn app() -> Element {
                             }
                             div { class: "digit-keys",
                                 button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
-                                button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" }
+                                button { class: "calculator-key key-dot", onclick: move |_| val.write().push('.'), "●" }
                                 for k in 1..10 {
                                     button {
                                         class: "calculator-key {k}",
@@ -120,7 +120,7 @@ fn app() -> Element {
                             button { class: "calculator-key key-add", onclick: move |_| input_operator("+"), "+" }
                             button {
                                 class: "calculator-key key-equals",
-                                onclick: move |_| val.set(format!("{}", calc_val(val.as_str()))),
+                                onclick: move |_| val.set(format!("{}", calc_val(val().as_str()))),
                                 "="
                             }
                         }

+ 2 - 2
examples/control_focus.rs

@@ -10,9 +10,9 @@ fn app() -> Element {
     let elements = use_signal(Vec::<Rc<MountedData>>::new);
     let running = use_signal(|| true);
 
-    use_future(|| async move {
+    use_future(move || async move {
         let mut focused = 0;
-        if *running.current() {
+        if *running() {
             loop {
                 tokio::time::sleep(std::time::Duration::from_millis(10)).await;
                 if let Some(element) = elements.with(|f| f.get(focused).cloned()) {

+ 6 - 6
examples/counter.rs

@@ -13,22 +13,22 @@ fn app() -> Element {
 
     render! {
         div {
-            button { onclick: move |_| counters.make_mut().push(0), "Add counter" }
-            button { onclick: move |_| { counters.make_mut().pop(); }, "Remove counter" }
+            button { onclick: move |_| counters.write().push(0), "Add counter" }
+            button { onclick: move |_| { counters.write().pop(); }, "Remove counter" }
             p { "Total: {sum}" }
             for (i, counter) in counters.iter().enumerate() {
                 li {
-                    button { onclick: move |_| counters.make_mut()[i] -= 1, "-1" }
+                    button { onclick: move |_| counters.write()[i] -= 1, "-1" }
                     input {
                         value: "{counter}",
                         oninput: move |e| {
                             if let Ok(value) = e.value().parse::<usize>() {
-                                counters.make_mut()[i] = value;
+                                counters.write()[i] = value;
                             }
                         }
                     }
-                    button { onclick: move |_| counters.make_mut()[i] += 1, "+1" }
-                    button { onclick: move |_| { counters.make_mut().remove(i); }, "x" }
+                    button { onclick: move |_| counters.write()[i] += 1, "+1" }
+                    button { onclick: move |_| { counters.write().remove(i); }, "x" }
                 }
             }
         }

+ 4 - 9
examples/crm.rs

@@ -27,7 +27,7 @@ pub struct Client {
 type ClientContext = Vec<Client>;
 
 #[component]
-fn App(props: ()) -> Element {
+fn App() -> Element {
     use_shared_state_provider::<ClientContext>(Default::default);
 
     render! {
@@ -58,15 +58,10 @@ fn ClientList() -> Element {
 
     rsx! {
         h2 { "List of Clients" }
-
         Link { to: Route::ClientAdd {}, class: "pure-button pure-button-primary", "Add Client" }
         Link { to: Route::Settings {}, class: "pure-button", "Settings" }
-
         for client in clients.read().iter() {
-            div {
-                class: "client",
-                style: "margin-bottom: 50px",
-
+            div { class: "client", style: "margin-bottom: 50px",
                 p { "Name: {client.first_name} {client.last_name}" }
                 p { "Description: {client.description}" }
             }
@@ -75,7 +70,7 @@ fn ClientList() -> Element {
 }
 
 #[component]
-fn ClientAdd(props: ()) -> Element {
+fn ClientAdd() -> Element {
     let clients = use_shared_state::<ClientContext>().unwrap();
     let first_name = use_signal(String::new);
     let last_name = use_signal(String::new);
@@ -142,7 +137,7 @@ fn ClientAdd(props: ()) -> Element {
 }
 
 #[component]
-fn Settings(props: ()) -> Element {
+fn Settings() -> Element {
     let clients = use_shared_state::<ClientContext>().unwrap();
 
     rsx! {

+ 3 - 7
examples/disabled.rs

@@ -9,17 +9,13 @@ fn app() -> Element {
 
     rsx! {
         div {
-            button {
-                onclick: move |_| disabled.set(!disabled),
+            button { onclick: move |_| disabled.toggle(),
                 "click to "
-                if disabled == true { "enable" } else { "disable" }
+                if *disabled() { "enable" } else { "disable" }
                 " the lower button"
             }
 
-            button {
-                disabled: "{disabled}",
-                "lower button"
-            }
+            button { disabled, "lower button" }
         }
     }
 }

+ 2 - 3
examples/dog_app.rs

@@ -2,7 +2,7 @@ use dioxus::prelude::*;
 use std::collections::HashMap;
 
 fn main() {
-    dioxus_desktop::launch(|cx| render!(AppRoot {}));
+    dioxus_desktop::launch(app);
 }
 
 #[derive(Debug, Clone, PartialEq, serde::Deserialize)]
@@ -10,8 +10,7 @@ struct ListBreeds {
     message: HashMap<String, Vec<String>>,
 }
 
-#[component]
-fn AppRoot(_: ()) -> Element {
+fn app() -> Element {
     let breed = use_signal(|| "deerhound".to_string());
 
     let breeds = use_future(|| async move {

+ 1 - 2
examples/error_handle.rs

@@ -4,8 +4,7 @@ fn main() {
     dioxus_desktop::launch(App);
 }
 
-#[component]
-fn App(_: ()) -> Element {
+fn app() -> Element {
     rsx! {
         ErrorBoundary {
             handle_error: |error: CapturedError| rsx! {"Found error {error}"},

+ 0 - 57
examples/fermi.rs

@@ -1,57 +0,0 @@
-#![allow(non_snake_case)]
-
-use dioxus::prelude::*;
-use fermi::*;
-
-fn main() {
-    dioxus_desktop::launch(app)
-}
-
-static NAME: Atom<String> = Atom(|_| "world".to_string());
-
-fn app() -> Element {
-    use_init_atom_root(cx);
-    let name = use_read(&NAME);
-
-    rsx! {
-        div { "hello {name}!" }
-        Child {}
-        ChildWithRef {}
-    }
-}
-
-fn Child() -> Element {
-    let set_name = use_set(&NAME);
-
-    rsx! {
-        button {
-            onclick: move |_| set_name("dioxus".to_string()),
-            "reset name"
-        }
-    }
-}
-
-static NAMES: AtomRef<Vec<String>> = AtomRef(|_| vec!["world".to_string()]);
-
-fn ChildWithRef() -> Element {
-    let names = use_atom_ref(&NAMES);
-
-    rsx! {
-        div {
-            ul {
-                for name in names.read().iter() {
-                    li { "hello: {name}" }
-                }
-            }
-            button {
-                onclick: move |_| {
-                    let names = names.clone();
-                    cx.spawn(async move {
-                        names.write().push("asd".to_string());
-                    })
-                },
-                "Add name"
-            }
-        }
-    }
-}

+ 5 - 6
examples/file_explorer.rs

@@ -12,20 +12,19 @@ use dioxus::prelude::*;
 use dioxus_desktop::{Config, WindowBuilder};
 
 fn main() {
-    dioxus_desktop::launch_cfg(
-        app,
-        Config::new().with_window(WindowBuilder::new().with_resizable(true)),
-    );
+    Config::new()
+        .with_window(WindowBuilder::new().with_resizable(true))
+        .launch(app)
 }
 
 const _STYLE: &str = manganis::mg!(file("./examples/assets/fileexplorer.css"));
 
-fn app() -> Element {
+fn app(_props: ()) -> Element {
     let files = use_signal(Files::new);
 
     rsx! {
         div {
-            link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet", }
+            link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet" }
             header {
                 i { class: "material-icons icon-menu", "menu" }
                 h1 { "Files: ", {files.read().current()} }

+ 26 - 34
examples/file_upload.rs

@@ -9,16 +9,33 @@ fn main() {
 
 fn App() -> Element {
     let enable_directory_upload = use_signal(|| false);
-    let files_uploaded: Signal<Vec<String>> = use_signal(Vec::new);
+    let files_uploaded = use_signal(|| Vec::new() as Vec<String>);
+
+    let upload_files = move |evt: FormEvent| async move {
+        for file_name in evt.files().unwrap().files() {
+            // no files on form inputs?
+            sleep(std::time::Duration::from_secs(1)).await;
+            files_uploaded.write().push(file_name);
+        }
+    };
+
+    let handle_file_drop = move |evt: DragEvent| async move {
+        if let Some(file_engine) = &evt.files() {
+            let files = file_engine.files();
+            for file_name in &files {
+                if let Some(file) = file_engine.read_file_to_string(file_name).await {
+                    files_uploaded.write().push(file);
+                }
+            }
+        }
+    };
 
     rsx! {
         label {
             input {
                 r#type: "checkbox",
-                checked: "{enable_directory_upload}",
-                oninput: move |evt| {
-                    enable_directory_upload.set(evt.value().parse().unwrap());
-                },
+                checked: enable_directory_upload,
+                oninput: move |evt| enable_directory_upload.set(evt.value().parse().unwrap()),
             },
             "Enable directory upload"
         }
@@ -27,41 +44,16 @@ fn App() -> Element {
             r#type: "file",
             accept: ".txt,.rs",
             multiple: true,
-            directory: **enable_directory_upload,
-            onchange: |evt| {
-                to_owned![files_uploaded];
-                async move {
-                    if let Some(file_engine) = &evt.files() {
-                        let files = file_engine.files();
-                        for file_name in files {
-                            sleep(std::time::Duration::from_secs(1)).await;
-                            files_uploaded.write().push(file_name);
-                        }
-                    }
-                }
-            },
+            directory: enable_directory_upload,
+            onchange: upload_files,
         }
         div {
             width: "100px",
             height: "100px",
             border: "1px solid black",
             prevent_default: "ondrop dragover dragenter",
-            ondrop: move |evt| {
-                to_owned![files_uploaded];
-                async move {
-                    if let Some(file_engine) = &evt.files() {
-                        let files = file_engine.files();
-                        for file_name in &files {
-                            if let Some(file) = file_engine.read_file_to_string(file_name).await{
-                                files_uploaded.write().push(file);
-                            }
-                        }
-                    }
-                }
-            },
-            ondragover: move |event: DragEvent| {
-                event.stop_propagation();
-            },
+            ondrop: handle_file_drop,
+            ondragover: move |event| event.stop_propagation(),
             "Drop files here"
         }
 

+ 7 - 7
examples/filedragdrop.rs

@@ -2,15 +2,15 @@ use dioxus::prelude::*;
 use dioxus_desktop::Config;
 
 fn main() {
-    let cfg = Config::new().with_file_drop_handler(|_w, e| {
-        println!("{e:?}");
-        true
-    });
-
-    dioxus_desktop::launch_with_props(app, (), cfg);
+    Config::new()
+        .with_file_drop_handler(|_w, e| {
+            println!("{e:?}");
+            true
+        })
+        .launch(app)
 }
 
-fn app() -> Element {
+fn app(_props: ()) -> Element {
     rsx!(
         div {
             h1 { "drag a file here and check your console" }

+ 11 - 14
examples/flat_router.rs

@@ -5,20 +5,17 @@ use dioxus_router::prelude::*;
 fn main() {
     env_logger::init();
 
-    let cfg = Config::new().with_window(
-        WindowBuilder::new()
-            .with_inner_size(LogicalSize::new(600, 1000))
-            .with_resizable(false),
-    );
-
-    dioxus_desktop::launch_cfg(App, cfg)
-}
-
-#[component]
-fn App() -> Element {
-    render! {
-        Router::<Route> {}
-    }
+    Config::new()
+        .with_window(
+            WindowBuilder::new()
+                .with_inner_size(LogicalSize::new(600, 1000))
+                .with_resizable(false),
+        )
+        .launch(|| {
+            render! {
+                Router::<Route> {}
+            }
+        });
 }
 
 #[derive(Routable, Clone)]

+ 4 - 4
examples/generic_component.rs

@@ -12,13 +12,13 @@ fn app() -> Element {
     }
 }
 
-#[derive(PartialEq, Props)]
-struct GenericChildProps<T: Display + PartialEq> {
+#[derive(PartialEq, Props, Clone)]
+struct GenericChildProps<T: Display + PartialEq + Clone + 'static> {
     data: T,
 }
 
-fn generic_child<T: Display + PartialEq>(cx: Scope<GenericChildProps<T>>) -> Element {
+fn generic_child<T: Display + PartialEq + Clone>(props: GenericChildProps<T>) -> Element {
     render! {
-        div { "{&cx.props.data}" }
+        div { "{&props.data}" }
     }
 }

+ 10 - 9
examples/hydration.rs

@@ -13,23 +13,24 @@ use dioxus::prelude::*;
 use dioxus_desktop::Config;
 
 fn main() {
-    let mut vdom = VirtualDom::new(app);
-    let _ = vdom.rebuild();
-    let content = dioxus_ssr::pre_render(&vdom);
+    Config::new()
+        .with_prerendered({
+            // We build the dom a first time, then pre-render it to HTML
+            let pre_rendered_dom = VirtualDom::prebuilt(app);
 
-    dioxus_desktop::launch_cfg(app, Config::new().with_prerendered(content));
+            // We then launch the app with the pre-rendered HTML
+            dioxus_ssr::pre_render(&pre_rendered_dom)
+        })
+        .launch(app);
 }
 
 fn app() -> Element {
-    let val = use_signal(|| 0);
+    let mut val = use_signal(|| 0);
 
     rsx! {
         div {
             h1 { "hello world. Count: {val}" }
-            button {
-                onclick: move |_| *val.make_mut() += 1,
-                "click to increment"
-            }
+            button { onclick: move |_| val += 1, "click to increment" }
         }
     }
 }

+ 15 - 19
examples/read_size.rs

@@ -26,35 +26,31 @@ fn main() {
 }
 
 fn app() -> Element {
-    let div_element: Signal<Option<Rc<MountedData>>> = use_signal(|| None);
+    let div_element = use_signal(|| None as Option<Rc<MountedData>>);
+    let dimensions = use_signal(Rect::zero);
 
-    let dimentions = use_signal(Rect::zero);
+    let read_dims = move |_| async move {
+        let read = div_element.read();
+        let client_rect = read.as_ref().map(|el| el.get_client_rect());
+        if let Some(client_rect) = client_rect {
+            if let Ok(rect) = client_rect.await {
+                dimensions.set(rect);
+            }
+        }
+    };
 
     rsx!(
         div {
             width: "50%",
             height: "50%",
             background_color: "red",
-            onmounted: move |cx| {
-                div_element.set(Some(cx.inner().clone()));
-            },
-            "This element is {dimentions.read():?}"
+            onmounted: move |cx| div_element.set(Some(cx.inner().clone())),
+            "This element is {dimensions.read():?}"
         }
 
         button {
-            onclick: move |_| {
-                to_owned![div_element, dimentions];
-                async move {
-                    let read = div_element.read();
-                    let client_rect = read.as_ref().map(|el| el.get_client_rect());
-                    if let Some(client_rect) = client_rect {
-                        if let Ok(rect) = client_rect.await {
-                            dimentions.set(rect);
-                        }
-                    }
-                }
-            },
-            "Read dimentions"
+            onclick: read_dims,
+            "Read dimensions"
         }
     )
 }

+ 0 - 58
examples/rsx_compile_fail.rs

@@ -1,58 +0,0 @@
-//! This example just flexes the ability to use arbitrary expressions within RSX.
-//! It also proves that lifetimes work properly, especially when used with use_ref
-
-use dioxus::prelude::*;
-
-fn main() {
-    let mut vdom = VirtualDom::new(example);
-    _ = vdom.rebuild();
-
-    let mut renderer = dioxus_ssr::Renderer::new();
-    renderer.pretty = true;
-    renderer.render(&vdom);
-}
-
-fn example() -> Element {
-    let items = use_signal(|| {
-        vec![Thing {
-            a: "asd".to_string(),
-            b: 10,
-        }]
-    });
-
-    let things = use_signal(|| {
-        vec![Thing {
-            a: "asd".to_string(),
-            b: 10,
-        }]
-    });
-    let things_list = things.read();
-
-    let mything = use_signal(|| Some(String::from("asd")));
-    let mything_read = mything.read();
-
-    rsx!(
-        div {
-            div { id: "asd",
-                "your neighborhood spiderman"
-
-                for item in items.iter().cycle().take(5) {
-                    div { "{item.a}" }
-                }
-
-                for thing in things_list.iter() {
-                    div { "{thing.a}" "{thing.b}" }
-                }
-
-                if let Some(f) = mything_read.as_ref() {
-                    div { "{f}" }
-                }
-            }
-        }
-    ))
-}
-
-struct Thing {
-    a: String,
-    b: u32,
-}

+ 5 - 10
examples/rsx_usage.rs

@@ -241,12 +241,10 @@ fn lowercase_helper() -> Element {
 
 mod baller {
     use super::*;
-    #[derive(Props, PartialEq, Eq)]
-    pub struct BallerProps {}
 
     #[component]
     /// This component totally balls
-    pub fn Baller(props: BallerProps) -> Element {
+    pub fn Baller() -> Element {
         todo!()
     }
 
@@ -259,16 +257,13 @@ mod baller {
     }
 }
 
-#[derive(Props)]
-pub struct TallerProps<'a> {
+/// Documention for this component is visible within the rsx macro
+#[component]
+pub fn Taller(
     /// Fields are documented and accessible in rsx!
     a: &'static str,
     children: Element,
-}
-
-/// Documention for this component is visible within the rsx macro
-#[component]
-pub fn Taller(props: TallerProps) -> Element {
+) -> Element {
     rsx! {
         {&cx.props.children}
     }

+ 1 - 1
examples/scroll_to_top.rs

@@ -19,7 +19,7 @@ fn app() -> Element {
             }
 
             button {
-                onclick: async move |_| move {
+                onclick: move |_| async move {
                     if let Some(header) = header_element.read().as_ref().cloned() {
                         let _ = header.scroll_to(ScrollBehavior::Smooth).await;
                     }

+ 13 - 13
examples/suspense.rs

@@ -17,18 +17,13 @@ use dioxus::prelude::*;
 use dioxus_desktop::{Config, LogicalSize, WindowBuilder};
 
 fn main() {
-    let cfg = Config::new().with_window(
-        WindowBuilder::new()
-            .with_title("Doggo Fetcher")
-            .with_inner_size(LogicalSize::new(600.0, 800.0)),
-    );
-
-    dioxus_desktop::launch_cfg(app, cfg);
-}
-
-#[derive(serde::Deserialize)]
-struct DogApi {
-    message: String,
+    Config::new()
+        .with_window(
+            WindowBuilder::new()
+                .with_title("Doggo Fetcher")
+                .with_inner_size(LogicalSize::new(600.0, 800.0)),
+        )
+        .launch(app)
 }
 
 fn app() -> Element {
@@ -54,6 +49,11 @@ fn app() -> Element {
 /// actually renders the data.
 fn Doggo() -> Element {
     let fut = use_future(|_| async move {
+        #[derive(serde::Deserialize)]
+        struct DogApi {
+            message: String,
+        }
+
         reqwest::get("https://dog.ceo/api/breeds/image/random/")
             .await
             .unwrap()
@@ -61,7 +61,7 @@ fn Doggo() -> Element {
             .await
     });
 
-    cx.render(match fut.value() {
+    match fut.value() {
         Some(Ok(resp)) => rsx! {
             button {
                 onclick: move |_| fut.restart(),

+ 73 - 71
examples/svg_basic.rs

@@ -1,77 +1,79 @@
 use dioxus::prelude::*;
 
 fn app() -> Element {
-    rsx!( svg {
-        width: "200",
-        height: "250",
-        xmlns: "http://www.w3.org/2000/svg",
-        version: "1.1",
-        rect {
-            x: "10",
-            y: "10",
-            width: "30",
-            height: "30",
-            stroke: "black",
-            fill: "transparent",
-            stroke_width: "5",
-        }
-        rect {
-            x: "60",
-            y: "10",
-            width: "30",
-            height: "30",
-            stroke: "black",
-            fill: "transparent",
-            stroke_width: "5",
-        }
-        circle {
-            cx: "25",
-            cy: "75",
-            r: "20",
-            stroke: "red",
-            fill: "transparent",
-            stroke_width: "5",
-        }
-        ellipse {
-            cx: "75",
-            cy: "75",
-            rx: "20",
-            ry: "5",
-            stroke: "red",
-            fill: "transparent",
-            stroke_width: "5",
-        }
-        line {
-            x1: "10",
-            x2: "50",
-            y1: "110",
-            y2: "150",
-            stroke: "orange",
-            stroke_width: "5",
-        }
-        polyline {
-            points: "60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145",
-            stroke: "orange",
-            fill: "transparent",
-            stroke_width: "5",
-        }
-        polygon {
-            points: "50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180",
-            stroke: "green",
-            fill: "transparent",
-            stroke_width: "5",
-        }
-        path {
-            d: "M20,230 Q40,205 50,230 T90,230",
-            fill: "none",
-            stroke: "blue",
-            stroke_width: "5",
-        }
-        path {
-            d: "M9.00001 9C9 62 103.5 124 103.5 178",
-            stroke: "#3CC4DC",
-            "stroke-linecap": "square",
-            "stroke-width": "square",
+    rsx! {
+        svg {
+            width: "200",
+            height: "250",
+            xmlns: "http://www.w3.org/2000/svg",
+            version: "1.1",
+            rect {
+                x: "10",
+                y: "10",
+                width: "30",
+                height: "30",
+                stroke: "black",
+                fill: "transparent",
+                stroke_width: "5",
+            }
+            rect {
+                x: "60",
+                y: "10",
+                width: "30",
+                height: "30",
+                stroke: "black",
+                fill: "transparent",
+                stroke_width: "5",
+            }
+            circle {
+                cx: "25",
+                cy: "75",
+                r: "20",
+                stroke: "red",
+                fill: "transparent",
+                stroke_width: "5",
+            }
+            ellipse {
+                cx: "75",
+                cy: "75",
+                rx: "20",
+                ry: "5",
+                stroke: "red",
+                fill: "transparent",
+                stroke_width: "5",
+            }
+            line {
+                x1: "10",
+                x2: "50",
+                y1: "110",
+                y2: "150",
+                stroke: "orange",
+                stroke_width: "5",
+            }
+            polyline {
+                points: "60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145",
+                stroke: "orange",
+                fill: "transparent",
+                stroke_width: "5",
+            }
+            polygon {
+                points: "50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180",
+                stroke: "green",
+                fill: "transparent",
+                stroke_width: "5",
+            }
+            path {
+                d: "M20,230 Q40,205 50,230 T90,230",
+                fill: "none",
+                stroke: "blue",
+                stroke_width: "5",
+            }
+            path {
+                d: "M9.00001 9C9 62 103.5 124 103.5 178",
+                stroke: "#3CC4DC",
+                "stroke-linecap": "square",
+                "stroke-width": "square",
+            }
         }
     }
 }

+ 1 - 1
examples/todomvc.rs

@@ -21,7 +21,7 @@ pub struct TodoItem {
     pub contents: String,
 }
 
-pub fn app(_props: ()) -> Element {
+pub fn app() -> Element {
     let todos = use_signal(|| HashMap::<u32, TodoItem>::new());
     let filter = use_signal(|| FilterState::All);
 

+ 20 - 30
examples/window_event.rs

@@ -1,34 +1,25 @@
 use dioxus::prelude::*;
-use dioxus_desktop::{Config, WindowBuilder};
+use dioxus_desktop::{window, Config, WindowBuilder};
 
 fn main() {
-    let cfg = Config::new().with_window(
-        WindowBuilder::new()
-            .with_title("Borderless Window")
-            .with_decorations(false),
-    );
-
-    dioxus_desktop::launch_cfg(app, cfg);
+    Config::new()
+        .with_window(
+            WindowBuilder::new()
+                .with_title("Borderless Window")
+                .with_decorations(false),
+        )
+        .launch(app)
 }
 
 fn app() -> Element {
-    let window = dioxus_desktop::use_window(cx);
-
-    // if you want to make window fullscreen, you need close the resizable.
-    // window.set_fullscreen(true);
-    // window.set_resizable(false);
-
     let fullscreen = use_signal(|| false);
     let always_on_top = use_signal(|| false);
     let decorations = use_signal(|| false);
 
     rsx!(
         link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }
-        header {
-            class: "text-gray-400 bg-gray-900 body-font",
-            onmousedown: move |_| window.drag(),
-            div {
-                class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center",
+        header { class: "text-gray-400 bg-gray-900 body-font", onmousedown: move |_| window().drag(),
+            div { class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center",
                 a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0",
                     span { class: "ml-3 text-xl", "Dioxus"}
                 }
@@ -36,24 +27,23 @@ fn app() -> Element {
                 button {
                     class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
                     onmousedown: |evt| evt.stop_propagation(),
-                    onclick: move |_| window.set_minimized(true),
+                    onclick: move |_| window().set_minimized(true),
                     "Minimize"
                 }
                 button {
                     class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
                     onmousedown: |evt| evt.stop_propagation(),
                     onclick: move |_| {
-
-                        window.set_fullscreen(!**fullscreen);
-                        window.set_resizable(**fullscreen);
-                        fullscreen.modify(|f| !*f);
+                        window().set_fullscreen(!*fullscreen());
+                        window().set_resizable(*fullscreen());
+                        fullscreen.toggle();
                     },
                     "Fullscreen"
                 }
                 button {
                     class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
                     onmousedown: |evt| evt.stop_propagation(),
-                    onclick: move |_| window.close(),
+                    onclick: move |_| window().close(),
                     "Close"
                 }
             }
@@ -68,8 +58,8 @@ fn app() -> Element {
                         class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
                         onmousedown: |evt| evt.stop_propagation(),
                         onclick: move |_| {
-                            window.set_always_on_top(!always_on_top);
-                            always_on_top.set(!always_on_top);
+                            window().set_always_on_top(!*always_on_top());
+                            always_on_top.toggle();
                         },
                         "Always On Top"
                     }
@@ -79,8 +69,8 @@ fn app() -> Element {
                         class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
                         onmousedown: |evt| evt.stop_propagation(),
                         onclick: move |_| {
-                            window.set_decorations(!decorations);
-                            decorations.set(!decorations);
+                            window().set_decorations(!*decorations());
+                            decorations.toggle();
                         },
                         "Set Decorations"
                     }
@@ -89,7 +79,7 @@ fn app() -> Element {
                     button {
                         class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
                         onmousedown: |evt| evt.stop_propagation(),
-                        onclick: move |_| window.set_title("Dioxus Application"),
+                        onclick: move |_| window().set_title("Dioxus Application"),
                         "Change Title"
                     }
                 }

+ 12 - 16
examples/window_focus.rs

@@ -5,37 +5,33 @@ use dioxus_desktop::use_wry_event_handler;
 use dioxus_desktop::{Config, WindowCloseBehaviour};
 
 fn main() {
-    let cfg = Config::new().with_close_behaviour(WindowCloseBehaviour::CloseWindow);
-
-    dioxus_desktop::launch_cfg(app, cfg);
+    Config::new()
+        .with_close_behaviour(WindowCloseBehaviour::CloseWindow)
+        .launch(app)
 }
 
 fn app() -> Element {
     let focused = use_signal(|| false);
 
-    use_wry_event_handler(move |event, _| {
-        if let WryEvent::WindowEvent {
+    use_wry_event_handler(move |event, _| match event {
+        WryEvent::WindowEvent {
             event: WindowEvent::Focused(new_focused),
             ..
-        } = event
-        {
-            focused.set(*new_focused);
-        }
+        } => focused.set(*new_focused),
+        _ => {}
     });
 
     rsx! {
-        div{
+        div {
             width: "100%",
             height: "100%",
             display: "flex",
             flex_direction: "column",
             align_items: "center",
-            {
-                if *focused.get() {
-                    "This window is focused!"
-                } else {
-                    "This window is not focused!"
-                }
+            if *focused() {
+                "This window is focused!"
+            } else {
+                "This window is not focused!"
             }
         }
     }

+ 1 - 1
examples/window_zoom.rs

@@ -11,7 +11,7 @@ fn app() -> Element {
         input {
             r#type: "number",
             value: "{level}",
-            oninput: |e| {
+            oninput: move |e| {
                 if let Ok(new_zoom) = e.value().parse::<f64>() {
                     level.set(new_zoom);
                     dioxus_desktop::window().webview.zoom(new_zoom);

+ 15 - 0
packages/core/src/virtual_dom.rs

@@ -230,6 +230,13 @@ impl VirtualDom {
         Self::new_with_props(|app| app(), app)
     }
 
+    /// Create a new virtualdom and build it immediately
+    pub fn prebuilt(app: fn() -> Element) -> Self {
+        let mut dom = Self::new(app);
+        dom.rebuild_in_place();
+        dom
+    }
+
     /// Create a new VirtualDom with the given properties for the root component.
     ///
     /// # Description
@@ -568,6 +575,14 @@ impl VirtualDom {
         to.append_children(ElementId(0), m);
     }
 
+    /// Rebuild the virtualdom without handling any of the mutations
+    ///
+    /// This is useful for testing purposes and in cases where you render the output of the virtualdom without
+    /// handling any of its mutations.
+    pub fn rebuild_in_place(&mut self) {
+        self.rebuild(&mut NoOpMutations);
+    }
+
     /// [`VirtualDom::rebuild`] to a vector of mutations for testing purposes
     pub fn rebuild_to_vec(&mut self) -> Mutations {
         let mut mutations = Mutations::default();

+ 3 - 3
packages/desktop/src/config.rs

@@ -1,7 +1,7 @@
 use std::borrow::Cow;
 use std::path::PathBuf;
 
-use dioxus_core::prelude::Component;
+use dioxus_core::prelude::{Component, Element};
 use tao::window::{Icon, WindowBuilder, WindowId};
 use wry::{
     http::{Request as HttpRequest, Response as HttpResponse},
@@ -74,8 +74,8 @@ impl Config {
     /// Launch a Dioxus app using the given component and config
     ///
     /// See the [`crate::launch::launch`] function for more details.
-    pub fn launch(self, root: Component<()>) {
-        crate::launch::launch_cfg(root, self)
+    pub fn launch(self, app: fn() -> Element) {
+        self.launch_with_props(|props| props(), app)
     }
 
     /// Launch a Dioxus app using the given component, config, and props

+ 14 - 14
packages/desktop/src/hooks.rs

@@ -2,6 +2,7 @@ use crate::{
     assets::*, ipc::UserWindowEvent, shortcut::IntoAccelerator, window, DesktopContext,
     ShortcutHandle, ShortcutRegistryError, WryEventHandler,
 };
+use dioxus_core::use_hook;
 use tao::{event::Event, event_loop::EventLoopWindowTarget};
 use wry::RequestAsyncResponder;
 
@@ -12,22 +13,21 @@ use wry::RequestAsyncResponder;
 //         .unwrap()
 // }
 
-// /// Get a closure that executes any JavaScript in the WebView context.
-// pub fn use_wry_event_handler(
-//     ,
-//     handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
-// ) -> &WryEventHandler {
-//     cx.use_hook(move || {
-//         let desktop = window();
+/// Get a closure that executes any JavaScript in the WebView context.
+pub fn use_wry_event_handler(
+    handler: impl FnMut(&Event<UserWindowEvent>, &EventLoopWindowTarget<UserWindowEvent>) + 'static,
+) -> WryEventHandler {
+    use_hook(move || {
+        let desktop = window();
 
-//         let id = desktop.create_wry_event_handler(handler);
+        let id = desktop.create_wry_event_handler(handler);
 
-//         WryEventHandler {
-//             handlers: desktop.shared.event_handlers.clone(),
-//             id,
-//         }
-//     })
-// }
+        WryEventHandler {
+            handlers: desktop.shared.event_handlers.clone(),
+            id,
+        }
+    })
+}
 
 // /// Provide a callback to handle asset loading yourself.
 // ///

+ 4 - 4
packages/desktop/src/launch.rs

@@ -23,8 +23,8 @@ use tao::event::{Event, StartCause, WindowEvent};
 ///     })
 /// }
 /// ```
-pub fn launch(root: fn() -> Element) {
-    launch_with_props(|root| root(), root, Config::default())
+pub fn launch(app: fn() -> Element) {
+    launch_with_props(|root| root(), app, Config::default())
 }
 
 /// Launch the WebView and run the event loop, with configuration.
@@ -47,8 +47,8 @@ pub fn launch(root: fn() -> Element) {
 ///     })
 /// }
 /// ```
-pub fn launch_cfg(root: Component, config_builder: Config) {
-    launch_with_props(root, (), config_builder)
+pub fn launch_cfg(app: fn() -> Element, config_builder: Config) {
+    launch_with_props(|props| props(), app, config_builder)
 }
 
 /// Launch the WebView and run the event loop, with configuration and root props.

+ 2 - 0
packages/desktop/src/lib.rs

@@ -46,3 +46,5 @@ pub use desktop_context::{
 // pub use hooks::{use_asset_handler, use_global_shortcut, use_window, use_wry_event_handler};
 pub use shortcut::{ShortcutHandle, ShortcutId, ShortcutRegistryError};
 pub use wry::RequestAsyncResponder;
+
+pub use hooks::*;

+ 14 - 2
packages/signals/src/signal.rs

@@ -7,8 +7,11 @@ use std::{
 };
 
 use dioxus_core::{
-    prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
-    use_hook, ScopeId,
+    prelude::{
+        current_scope_id, has_context, provide_context, schedule_update_any, use_hook,
+        IntoAttributeValue,
+    },
+    ScopeId,
 };
 use generational_box::{GenerationalRef, GenerationalRefMut};
 
@@ -306,6 +309,15 @@ impl<T: 'static> Signal<T> {
     }
 }
 
+impl<T> IntoAttributeValue for Signal<T>
+where
+    T: Clone + IntoAttributeValue,
+{
+    fn into_value(self) -> dioxus_core::AttributeValue {
+        self.with(|f| f.clone().into_value())
+    }
+}
+
 impl<T: Clone + 'static> Signal<T> {
     /// Get the current value of the signal. This will subscribe the current scope to the signal.
     /// If the signal has been dropped, this will panic.