Răsfoiți Sursa

Merge branch 'upstream' into desktop-hot-reload

Evan Almloff 2 ani în urmă
părinte
comite
6c804cded7

+ 1 - 1
.github/workflows/main.yml

@@ -104,7 +104,7 @@ jobs:
       - uses: actions-rs/cargo@v1
         with:
           command: clippy
-          args: --workspace -- -D warnings
+          args: --workspace --examples --tests -- -D warnings
 
   # Coverage is disabled until we can fix it
   # coverage:

+ 2 - 2
examples/compose.rs

@@ -10,7 +10,7 @@ fn main() {
 
 fn app(cx: Scope) -> Element {
     let window = use_window(cx);
-    let emails_sent = use_ref(cx, || vec![]);
+    let emails_sent = use_ref(cx, Vec::new);
 
     let tx = use_coroutine(cx, |mut rx: UnboundedReceiver<String>| {
         to_owned![emails_sent];
@@ -56,7 +56,7 @@ struct ComposeProps {
 }
 
 fn compose(cx: Scope<ComposeProps>) -> Element {
-    let user_input = use_state(cx, || String::new());
+    let user_input = use_state(cx, String::new);
     let window = use_window(cx);
 
     cx.render(rsx! {

+ 0 - 40
examples/custom_element.rs

@@ -1,40 +0,0 @@
-//! This example shows to wrap a webcomponent / custom element with a component.
-//!
-//! Oftentimes, a third party library will provide a webcomponent that you want
-//! to use in your application. This example shows how to create that custom element
-//! directly with the raw_element method on NodeFactory.
-
-use dioxus::prelude::*;
-
-fn main() {
-    let mut dom = VirtualDom::new(app);
-    let _ = dom.rebuild();
-
-    let output = dioxus_ssr::render(&dom);
-
-    println!("{}", output);
-}
-
-fn app(cx: Scope) -> Element {
-    let g = cx.component(component, (), "component");
-    let c = cx.make_node(g);
-    cx.render(rsx! {
-        div { c }
-    })
-
-    // let nf = NodeFactory::new(cx);
-
-    // let mut attrs = dioxus::core::exports::bumpalo::collections::Vec::new_in(nf.bump());
-
-    // attrs.push(nf.attr("client-id", format_args!("abc123"), None, false));
-
-    // attrs.push(nf.attr("name", format_args!("bob"), None, false));
-
-    // attrs.push(nf.attr("age", format_args!("47"), None, false));
-
-    // Some(nf.raw_element("my-element", None, &[], attrs.into_bump_slice(), &[], None))
-}
-
-fn component(cx: Scope) -> Element {
-    todo!()
-}

+ 1 - 1
examples/fermi.rs

@@ -10,7 +10,7 @@ fn main() {
 static NAME: Atom<String> = |_| "world".to_string();
 
 fn app(cx: Scope) -> Element {
-    use_init_atom_root(&cx);
+    use_init_atom_root(cx);
     let name = use_read(cx, NAME);
 
     cx.render(rsx! {

+ 1 - 2
examples/multiwindow.rs

@@ -1,12 +1,11 @@
 use dioxus::prelude::*;
-use dioxus_desktop::{use_window, WindowBuilder};
 
 fn main() {
     dioxus_desktop::launch(app);
 }
 
 fn app(cx: Scope) -> Element {
-    let window = use_window(cx);
+    let window = dioxus_desktop::use_window(cx);
 
     cx.render(rsx! {
         div {

+ 1 - 1
examples/overlay.rs

@@ -1,5 +1,5 @@
 use dioxus::prelude::*;
-use dioxus_desktop::{tao::dpi::PhysicalPosition, use_window, Config, LogicalSize, WindowBuilder};
+use dioxus_desktop::{tao::dpi::PhysicalPosition, use_window, LogicalSize, WindowBuilder};
 
 fn main() {
     dioxus_desktop::launch_cfg(app, make_config());

+ 2 - 0
examples/simple_desktop.rs

@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use dioxus::prelude::*;
 use dioxus_router::*;
 

+ 3 - 0
packages/core/.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+    "rust-analyzer.checkOnSave.allTargets": false
+}

+ 25 - 14
packages/core/README.md

@@ -33,34 +33,45 @@ The `dioxus` crate exports the `rsx` macro which transforms a helpful, simpler s
 
 First, start with your app:
 
-```rust, ignore
+```rust
+# use dioxus::core::Mutations;
+use dioxus::prelude::*;
+
+// First, declare a root component
 fn app(cx: Scope) -> Element {
-    cx.render(rsx!( div { "hello world" } ))
+    cx.render(rsx!{
+        div { "hello world" }
+    })
 }
-```
 
-Then, we'll want to create a new VirtualDom using this app as the root component.
-
-```rust, ignore
-let mut dom = VirtualDom::new(app);
-```
+fn main() {
+    // Next, create a new VirtualDom using this app as the root component.
+    let mut dom = VirtualDom::new(app);
 
-To build the app into a stream of mutations, we'll use [`VirtualDom::rebuild`]:
+    // The initial render of the dom will generate a stream of edits for the real dom to apply
+    let mutations = dom.rebuild();
 
-```rust, ignore
-let mutations = dom.rebuild();
+    // Somehow, you can apply these edits to the real dom
+    apply_edits_to_real_dom(mutations);
+}
 
-apply_edits_to_real_dom(mutations);
+# fn apply_edits_to_real_dom(mutations: Mutations) {}
 ```
 
+
 We can then wait for any asynchronous components or pending futures using the `wait_for_work()` method. If we have a deadline, then we can use render_with_deadline instead:
+```rust
+# #![allow(unused)]
+# use dioxus::prelude::*;
 
-```rust, ignore
+# use std::time::Duration;
+# async fn wait(mut dom: VirtualDom) {
 // Wait for the dom to be marked dirty internally
 dom.wait_for_work().await;
 
 // Or wait for a deadline and then collect edits
-dom.render_with_deadline(tokio::time::sleep(Duration::from_millis(16)));
+let mutations = dom.render_with_deadline(tokio::time::sleep(Duration::from_millis(16)));
+# }
 ```
 
 If an event occurs from outside the VirtualDom while waiting for work, then we can cancel the wait using a `select!` block and inject the event.

+ 36 - 3
packages/core/src/virtual_dom.rs

@@ -24,7 +24,9 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future
 ///
 /// Components are defined as simple functions that take [`Scope`] and return an [`Element`].
 ///
-/// ```rust, ignore
+/// ```rust
+/// # use dioxus::prelude::*;
+///
 /// #[derive(Props, PartialEq)]
 /// struct AppProps {
 ///     title: String
@@ -39,7 +41,17 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future
 ///
 /// Components may be composed to make complex apps.
 ///
-/// ```rust, ignore
+/// ```rust
+/// # #![allow(unused)]
+/// # use dioxus::prelude::*;
+///
+/// # #[derive(Props, PartialEq)]
+/// # struct AppProps {
+/// #     title: String
+/// # }
+///
+/// static ROUTES: &str = "";
+///
 /// fn App(cx: Scope<AppProps>) -> Element {
 ///     cx.render(rsx!(
 ///         NavBar { routes: ROUTES }
@@ -47,12 +59,33 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future
 ///         Footer {}
 ///     ))
 /// }
+///
+/// #[inline_props]
+/// fn NavBar(cx: Scope, routes: &'static str) -> Element {
+///     cx.render(rsx! {
+///         div { "Routes: {routes}" }
+///     })
+/// }
+///
+/// fn Footer(cx: Scope) -> Element {
+///     cx.render(rsx! { div { "Footer" } })
+/// }
+///
+/// #[inline_props]
+/// fn Title<'a>(cx: Scope<'a>, children: Element<'a>) -> Element {
+///     cx.render(rsx! {
+///         div { id: "title", children }
+///     })
+/// }
 /// ```
 ///
 /// To start an app, create a [`VirtualDom`] and call [`VirtualDom::rebuild`] to get the list of edits required to
 /// draw the UI.
 ///
-/// ```rust, ignore
+/// ```rust
+/// # use dioxus::prelude::*;
+/// # fn App(cx: Scope) -> Element { cx.render(rsx! { div {} }) }
+///
 /// let mut vdom = VirtualDom::new(App);
 /// let edits = vdom.rebuild();
 /// ```

+ 1 - 1
packages/core/tests/attr_cleanup.rs

@@ -5,7 +5,7 @@
 use bumpalo::Bump;
 use dioxus::core::{ElementId, Mutation::*};
 use dioxus::prelude::*;
-use dioxus_core::{AttributeValue, BorrowedAttributeValue};
+use dioxus_core::BorrowedAttributeValue;
 
 #[test]
 fn attrs_cycle() {

+ 6 - 30
packages/core/tests/error_boundary.rs

@@ -1,13 +1,11 @@
+#![allow(non_snake_case)]
+
 use dioxus::prelude::*;
-use futures_util::Future;
 
 #[test]
 fn catches_panic() {
     let mut dom = VirtualDom::new(app);
-
-    let a = dom.rebuild();
-
-    dbg!(a);
+    _ = dom.rebuild();
 }
 
 fn app(cx: Scope) -> Element {
@@ -16,43 +14,21 @@ fn app(cx: Scope) -> Element {
             h1 { "Title" }
 
             NoneChild {}
+            ThrowChild {}
         }
     })
 }
 
-fn NoneChild(cx: Scope) -> Element {
+fn NoneChild(_cx: Scope) -> Element {
     None
 }
 
-fn PanicChild(cx: Scope) -> Element {
-    panic!("Rendering panicked for whatever reason");
-
-    cx.render(rsx! {
-        h1 { "It works!" }
-    })
-}
-
 fn ThrowChild(cx: Scope) -> Element {
     cx.throw(std::io::Error::new(std::io::ErrorKind::AddrInUse, "asd"))?;
 
-    let g: i32 = "123123".parse().throw(cx)?;
+    let _g: i32 = "123123".parse().throw(cx)?;
 
     cx.render(rsx! {
         div {}
     })
 }
-
-fn custom_allocator(cx: Scope) -> Element {
-    let g = String::new();
-
-    let p = g.as_str();
-
-    let g2 = cx.use_hook(|| 123);
-    // cx.spawn(async move {
-
-    //     //
-    //     // println!("Thig is {p}");
-    // });
-
-    None
-}

+ 7 - 218
packages/core/tests/miri_stress.rs

@@ -143,15 +143,15 @@ fn supports_async() {
     use tokio::time::sleep;
 
     fn app(cx: Scope) -> Element {
-        let colors = use_state(&cx, || vec!["green", "blue", "red"]);
-        let padding = use_state(&cx, || 10);
+        let colors = use_state(cx, || vec!["green", "blue", "red"]);
+        let padding = use_state(cx, || 10);
 
-        use_effect(&cx, colors, |colors| async move {
+        use_effect(cx, colors, |colors| async move {
             sleep(Duration::from_millis(1000)).await;
             colors.with_mut(|colors| colors.reverse());
         });
 
-        use_effect(&cx, padding, |padding| async move {
+        use_effect(cx, padding, |padding| async move {
             sleep(Duration::from_millis(10)).await;
             padding.with_mut(|padding| {
                 if *padding < 65 {
@@ -206,220 +206,9 @@ fn supports_async() {
         let mut dom = VirtualDom::new(app);
         let _ = dom.rebuild();
 
-        for x in 0..10 {
-            let _ = dom.wait_for_work().await;
-            let edits = dom.render_immediate();
+        for _ in 0..10 {
+            dom.wait_for_work().await;
+            let _edits = dom.render_immediate();
         }
     });
 }
-
-// #[test]
-// fn old_props_arent_stale() {
-//     fn app(cx: Scope) -> Element {
-//         dbg!("rendering parent");
-//         let cnt = cx.use_hook(|| 0);
-//         *cnt += 1;
-
-//         if *cnt == 1 {
-//             render!(div { Child { a: "abcdef".to_string() } })
-//         } else {
-//             render!(div { Child { a: "abcdef".to_string() } })
-//         }
-//     }
-
-//     #[derive(Props, PartialEq)]
-//     struct ChildProps {
-//         a: String,
-//     }
-//     fn Child(cx: Scope<ChildProps>) -> Element {
-//         dbg!("rendering child", &cx.props.a);
-//         render!(div { "child {cx.props.a}" })
-//     }
-
-//     let mut dom = new_dom(app, ());
-//     let _ = dom.rebuild();
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-
-//     dbg!("forcing update to child");
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
-//     dom.work_with_deadline(|| false);
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
-//     dom.work_with_deadline(|| false);
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
-//     dom.work_with_deadline(|| false);
-// }
-
-// #[test]
-// fn basic() {
-//     fn app(cx: Scope) -> Element {
-//         render!(div {
-//             Child { a: "abcdef".to_string() }
-//         })
-//     }
-
-//     #[derive(Props, PartialEq)]
-//     struct ChildProps {
-//         a: String,
-//     }
-
-//     fn Child(cx: Scope<ChildProps>) -> Element {
-//         dbg!("rendering child", &cx.props.a);
-//         render!(div { "child {cx.props.a}" })
-//     }
-
-//     let mut dom = new_dom(app, ());
-//     let _ = dom.rebuild();
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-// }
-
-// #[test]
-// fn leak_thru_children() {
-//     fn app(cx: Scope) -> Element {
-//         cx.render(rsx! {
-//             Child {
-//                 name: "asd".to_string(),
-//             }
-//         });
-//         cx.render(rsx! {
-//             div {}
-//         })
-//     }
-
-//     #[inline_props]
-//     fn Child(cx: Scope, name: String) -> Element {
-//         render!(div { "child {name}" })
-//     }
-
-//     let mut dom = new_dom(app, ());
-//     let _ = dom.rebuild();
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-
-//     dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//     dom.work_with_deadline(|| false);
-// }
-
-// #[test]
-// fn test_pass_thru() {
-//     #[inline_props]
-//     fn NavContainer<'a>(cx: Scope, children: Element<'a>) -> Element {
-//         cx.render(rsx! {
-//             header {
-//                 nav { children }
-//             }
-//         })
-//     }
-
-//     fn NavMenu(cx: Scope) -> Element {
-//         render!(            NavBrand {}
-//             div {
-//                 NavStart {}
-//                 NavEnd {}
-//             }
-//         )
-//     }
-
-//     fn NavBrand(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     fn NavStart(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     fn NavEnd(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     #[inline_props]
-//     fn MainContainer<'a>(
-//         cx: Scope,
-//         nav: Element<'a>,
-//         body: Element<'a>,
-//         footer: Element<'a>,
-//     ) -> Element {
-//         cx.render(rsx! {
-//             div {
-//                 class: "columns is-mobile",
-//                 div {
-//                     class: "column is-full",
-//                     nav,
-//                     body,
-//                     footer,
-//                 }
-//             }
-//         })
-//     }
-
-//     fn app(cx: Scope) -> Element {
-//         let nav = cx.render(rsx! {
-//             NavContainer {
-//                 NavMenu {}
-//             }
-//         });
-//         let body = cx.render(rsx! {
-//             div {}
-//         });
-//         let footer = cx.render(rsx! {
-//             div {}
-//         });
-
-//         cx.render(rsx! {
-//             MainContainer {
-//                 nav: nav,
-//                 body: body,
-//                 footer: footer,
-//             }
-//         })
-//     }
-
-//     let mut dom = new_dom(app, ());
-//     let _ = dom.rebuild();
-
-//     for _ in 0..40 {
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
-//         dom.work_with_deadline(|| false);
-
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
-//         dom.work_with_deadline(|| false);
-
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(2)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(2)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(2)));
-//         dom.work_with_deadline(|| false);
-
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(3)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(3)));
-//         dom.work_with_deadline(|| false);
-//         dom.handle_message(SchedulerMsg::Immediate(ScopeId(3)));
-//         dom.work_with_deadline(|| false);
-//     }
-// }

+ 10 - 16
packages/native-core/tests/miri_native.rs

@@ -1,5 +1,4 @@
 use dioxus::prelude::*;
-use dioxus_native_core::*;
 use dioxus_native_core::{
     node_ref::{AttributeMask, NodeView},
     real_dom::RealDom,
@@ -7,13 +6,10 @@ use dioxus_native_core::{
     NodeMask, SendAnyMap,
 };
 use dioxus_native_core_macro::{sorted_str_slice, State};
-use std::{
-    sync::{Arc, Mutex},
-    time::Duration,
-};
+use std::sync::{Arc, Mutex};
 use tokio::time::sleep;
 
-#[derive(Debug, Clone, PartialEq, Default)]
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
 pub struct BlablaState {}
 
 /// Font style are inherited by default if not specified otherwise by some of the supported attributes.
@@ -88,15 +84,15 @@ fn native_core_is_okay() {
     use std::time::Duration;
 
     fn app(cx: Scope) -> Element {
-        let colors = use_state(&cx, || vec!["green", "blue", "red"]);
-        let padding = use_state(&cx, || 10);
+        let colors = use_state(cx, || vec!["green", "blue", "red"]);
+        let padding = use_state(cx, || 10);
 
-        use_effect(&cx, colors, |colors| async move {
+        use_effect(cx, colors, |colors| async move {
             sleep(Duration::from_millis(1000)).await;
             colors.with_mut(|colors| colors.reverse());
         });
 
-        use_effect(&cx, padding, |padding| async move {
+        use_effect(cx, padding, |padding| async move {
             sleep(Duration::from_millis(10)).await;
             padding.with_mut(|padding| {
                 if *padding < 65 {
@@ -107,9 +103,9 @@ fn native_core_is_okay() {
             });
         });
 
-        let big = colors[0];
-        let mid = colors[1];
-        let small = colors[2];
+        let _big = colors[0];
+        let _mid = colors[1];
+        let _small = colors[2];
 
         cx.render(rsx! {
             blabla {}
@@ -128,17 +124,15 @@ fn native_core_is_okay() {
         let muts = dom.rebuild();
         let (to_update, _diff) = rdom.lock().unwrap().apply_mutations(muts);
 
-        let ctx = SendAnyMap::new();
         let ctx = SendAnyMap::new();
         rdom.lock().unwrap().update_state(to_update, ctx);
 
-        for x in 0..10 {
+        for _ in 0..10 {
             dom.wait_for_work().await;
 
             let mutations = dom.render_immediate();
             let (to_update, _diff) = rdom.lock().unwrap().apply_mutations(mutations);
 
-            let ctx = SendAnyMap::new();
             let ctx = SendAnyMap::new();
             rdom.lock().unwrap().update_state(to_update, ctx);
         }

+ 4 - 1
packages/web/src/dom.rs

@@ -234,7 +234,10 @@ pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -
             Rc::new(MouseData::from(event))
         }
         "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart"
-        | "drop" => Rc::new(DragData::from(event)),
+        | "drop" => {
+            let mouse = MouseData::from(event);
+            Rc::new(DragData { mouse })
+        }
 
         "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
         | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {