Browse Source

polish: clean up to web

Jonathan Kelley 3 years ago
parent
commit
b43a964

+ 1 - 0
packages/web/Cargo.toml

@@ -74,6 +74,7 @@ separator = "0.4.1"
 uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
 uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
 dioxus-hooks = { path = "../hooks" }
 dioxus-hooks = { path = "../hooks" }
 serde = { version = "1.0.126", features = ["derive"] }
 serde = { version = "1.0.126", features = ["derive"] }
+reqwest = { version = "0.11", features = ["json"] }
 
 
 # rand = { version="0.8.4", features=["small_rng"] }
 # rand = { version="0.8.4", features=["small_rng"] }
 # surf = { version = "2.3.1", default-features = false, features = [
 # surf = { version = "2.3.1", default-features = false, features = [

+ 17 - 40
packages/web/examples/async_web.rs

@@ -1,24 +1,13 @@
 //! Basic example that renders a simple VNode to the browser.
 //! Basic example that renders a simple VNode to the browser.
-
-use dioxus::events::on::MouseEvent;
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
 use dioxus_core::prelude::*;
 use dioxus_hooks::*;
 use dioxus_hooks::*;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
-// use wasm_timer;
-
-use std::future::Future;
-
-use std::{pin::Pin, time::Duration};
-
-use dioxus::prelude::*;
 
 
 fn main() {
 fn main() {
-    // Setup logging
     console_error_panic_hook::set_once();
     console_error_panic_hook::set_once();
     wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
     wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-
-    dioxus_web::launch(App, |c| c)
+    dioxus_web::launch(APP, |c| c)
 }
 }
 
 
 #[derive(serde::Deserialize)]
 #[derive(serde::Deserialize)]
@@ -26,14 +15,13 @@ struct DogApi {
     message: String,
     message: String,
 }
 }
 
 
-const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/";
-
-static App: FC<()> = |cx, props|{
+static APP: FC<()> = |cx, _props| {
     let state = use_state(cx, || 0);
     let state = use_state(cx, || 0);
 
 
-    let dog_node = use_suspense(
+    const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/";
+    let doggo = use_suspense(
         cx,
         cx,
-        || surf::get(ENDPOINT).recv_json::<DogApi>(),
+        || async { reqwest::get(ENDPOINT).await.unwrap().json::<DogApi>().await },
         |cx, res| match res {
         |cx, res| match res {
             Ok(res) => rsx!(
             Ok(res) => rsx!(
                 cx,
                 cx,
@@ -45,29 +33,18 @@ static App: FC<()> = |cx, props|{
         },
         },
     );
     );
 
 
-    cx.render(rsx! {
-        div { style: { align_items: "center" }
-            section { class: "py-12 px-4 text-center"
-                div { class: "w-full max-w-2xl mx-auto"
-                    span { class: "text-sm font-semibold"
-                        "count: {state}"
-                    }
-                    br {}
-                    div {
-                        button {
-                            onclick: move |_| state.set(state + 1)
-                            "incr"
-                        }
-                        br {}
-                        button {
-                            onclick: move |_| state.set(state - 1)
-                            "decr"
-                        }
-                    }
-                    div {
-                        h1{"doggo!"}
-                        {dog_node}
-                    }
+    rsx!(cx, div { align_items: "center"
+        section { class: "py-12 px-4 text-center"
+            div { class: "w-full max-w-2xl mx-auto"
+                span { class: "text-sm font-semibold"
+                    "count: {state}"
+                }
+                div {
+                    button { onclick: move |_| state.set(state + 1), "incr" }
+                    button { onclick: move |_| state.set(state - 1), "decr" }
+                }
+                div {
+                    {doggo}
                 }
                 }
             }
             }
         }
         }

+ 6 - 21
packages/web/examples/basic.rs

@@ -1,18 +1,9 @@
 //! Basic example that renders a simple VNode to the browser.
 //! Basic example that renders a simple VNode to the browser.
-
-// all these imports are done automatically with the `dioxus` crate and `prelude`
-// need to do them manually for this example
-use dioxus::events::on::MouseEvent;
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
 use dioxus_core::prelude::*;
 use dioxus_hooks::*;
 use dioxus_hooks::*;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
 
 
-use dioxus::prelude::*;
-use dioxus_web::*;
-use std::future::Future;
-use std::{pin::Pin, time::Duration};
-
 fn main() {
 fn main() {
     // Setup logging
     // Setup logging
     wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
     wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
@@ -22,12 +13,10 @@ fn main() {
     dioxus_web::launch(APP, |c| c)
     dioxus_web::launch(APP, |c| c)
 }
 }
 
 
-static APP: FC<()> = |cx, props| {
+static APP: FC<()> = |cx, _| {
     let mut count = use_state(cx, || 3);
     let mut count = use_state(cx, || 3);
-    let mut content = use_state(cx, || String::from("h1"));
-    let mut text_content = use_state(cx, || String::from("Hello, world!"));
-
-    log::debug!("running scope...");
+    let content = use_state(cx, || String::from("h1"));
+    let text_content = use_state(cx, || String::from("Hello, world!"));
 
 
     cx.render(rsx! {
     cx.render(rsx! {
         div {
         div {
@@ -39,8 +28,7 @@ static APP: FC<()> = |cx, props| {
                 oninput: move |e| text_content.set(e.value())
                 oninput: move |e| text_content.set(e.value())
             }
             }
 
 
-            br {}
-            {(0..10).map(|f| {
+            {(0..10).map(|_| {
                 rsx!(
                 rsx!(
                     button {
                     button {
                         onclick: move |_| count += 1,
                         onclick: move |_| count += 1,
@@ -74,7 +62,7 @@ static APP: FC<()> = |cx, props| {
 
 
             {render_bullets(cx)}
             {render_bullets(cx)}
 
 
-            Child {}
+            CHILD {}
         }
         }
     })
     })
 };
 };
@@ -97,7 +85,4 @@ fn render_list(cx: Context, count: usize) -> DomTree {
     rsx!(cx, ul { {items} })
     rsx!(cx, ul { {items} })
 }
 }
 
 
-static Child: FC<()> = |cx, props| {
-    // render
-    rsx!(cx, div {"hello child"})
-};
+static CHILD: FC<()> = |cx, _| rsx!(cx, div {"hello child"});

+ 31 - 26
packages/web/src/dom.rs

@@ -1,3 +1,12 @@
+//! Implementation of a renderer for Dioxus on the web.
+//!
+//! Oustanding todos:
+//! - Removing event listeners (delegation)
+//! - Passive event listeners
+//! - no-op event listener patch for safari
+//! - tests to ensure dyn_into works for various event types.
+//! - Partial delegation?>
+
 use dioxus_core::{
 use dioxus_core::{
     events::{SyntheticEvent, UserEvent},
     events::{SyntheticEvent, UserEvent},
     mutations::NodeRefMutation,
     mutations::NodeRefMutation,
@@ -29,7 +38,7 @@ pub struct WebsysDom {
     // map of listener types to number of those listeners
     // map of listener types to number of those listeners
     // This is roughly a delegater
     // This is roughly a delegater
     // TODO: check how infero delegates its events - some are more performant
     // TODO: check how infero delegates its events - some are more performant
-    listeners: FxHashMap<&'static str, (usize, Closure<dyn FnMut(&Event)>)>,
+    listeners: FxHashMap<&'static str, ListenerEntry>,
 
 
     // We need to make sure to add comments between text nodes
     // We need to make sure to add comments between text nodes
     // We ensure that the text siblings are patched by preventing the browser from merging
     // We ensure that the text siblings are patched by preventing the browser from merging
@@ -38,6 +47,9 @@ pub struct WebsysDom {
     //  -> https://github.com/facebook/react/pull/5753
     //  -> https://github.com/facebook/react/pull/5753
     last_node_was_text: bool,
     last_node_was_text: bool,
 }
 }
+
+type ListenerEntry = (usize, Closure<dyn FnMut(&Event)>);
+
 impl WebsysDom {
 impl WebsysDom {
     pub fn new(root: Element, cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
     pub fn new(root: Element, cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
         let document = load_document();
         let document = load_document();
@@ -92,7 +104,6 @@ impl WebsysDom {
 
 
     pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
     pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
         for edit in edits.drain(..) {
         for edit in edits.drain(..) {
-            // log::info!("Handling edit: {:#?}", edit);
             match edit {
             match edit {
                 DomEdit::PushRoot { id: root } => self.push(root),
                 DomEdit::PushRoot { id: root } => self.push(root),
                 DomEdit::PopRoot => self.pop(),
                 DomEdit::PopRoot => self.pop(),
@@ -423,34 +434,29 @@ impl WebsysDom {
 }
 }
 
 
 #[derive(Debug, Default)]
 #[derive(Debug, Default)]
-pub struct Stack {
-    pub list: Vec<Node>,
+struct Stack {
+    list: Vec<Node>,
 }
 }
 
 
 impl Stack {
 impl Stack {
     #[inline]
     #[inline]
-    pub fn with_capacity(cap: usize) -> Self {
+    fn with_capacity(cap: usize) -> Self {
         Stack {
         Stack {
             list: Vec::with_capacity(cap),
             list: Vec::with_capacity(cap),
         }
         }
     }
     }
 
 
     #[inline]
     #[inline]
-    pub fn push(&mut self, node: Node) {
+    fn push(&mut self, node: Node) {
         self.list.push(node);
         self.list.push(node);
     }
     }
 
 
     #[inline]
     #[inline]
-    pub fn pop(&mut self) -> Node {
+    fn pop(&mut self) -> Node {
         self.list.pop().unwrap()
         self.list.pop().unwrap()
     }
     }
 
 
-    #[inline]
-    pub fn clear(&mut self) {
-        self.list.clear();
-    }
-
-    pub fn top(&self) -> &Node {
+    fn top(&self) -> &Node {
         match self.list.last() {
         match self.list.last() {
             Some(a) => a,
             Some(a) => a,
             None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
             None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
@@ -458,6 +464,8 @@ impl Stack {
     }
     }
 }
 }
 
 
+// todo: some of these events are being casted to the wrong event type.
+// We need tests that simulate clicks/etc and make sure every event type works.
 fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
 fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
     use crate::events::*;
     use crate::events::*;
     use dioxus_core::events::on::*;
     use dioxus_core::events::on::*;
@@ -549,12 +557,13 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
 
 
     let typ = event.type_();
     let typ = event.type_();
 
 
-    log::debug!("Event type is {:?}", typ);
-
-    let attrs = target.attributes();
-    for x in 0..attrs.length() {
-        let attr: Attr = attrs.item(x).unwrap();
-        // log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
+    // TODO: clean this up
+    if cfg!(debug_assertions) {
+        let attrs = target.attributes();
+        for x in 0..attrs.length() {
+            let attr: Attr = attrs.item(x).unwrap();
+            // log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
+        }
     }
     }
 
 
     use anyhow::Context;
     use anyhow::Context;
@@ -576,12 +585,8 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
         .and_then(|raw_id| raw_id.parse::<u64>().ok())
         .and_then(|raw_id| raw_id.parse::<u64>().ok())
         .context("failed to parse real id")?;
         .context("failed to parse real id")?;
 
 
-    // Call the trigger
-    // log::debug!("decoded scope_id: {}, node_id: {:#?}", gi_id, real_id);
-
     let triggered_scope = gi_id;
     let triggered_scope = gi_id;
-    // let triggered_scope: ScopeId = KeyData::from_ffi(gi_id).into();
-    // log::debug!("Triggered scope is {:#?}", triggered_scope);
+
     Ok(UserEvent {
     Ok(UserEvent {
         name: event_name_from_typ(&typ),
         name: event_name_from_typ(&typ),
         event: virtual_event_from_websys_event(event.clone()),
         event: virtual_event_from_websys_event(event.clone()),
@@ -590,14 +595,14 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
     })
     })
 }
 }
 
 
-pub fn load_document() -> Document {
+pub(crate) fn load_document() -> Document {
     web_sys::window()
     web_sys::window()
         .expect("should have access to the Window")
         .expect("should have access to the Window")
         .document()
         .document()
         .expect("should have access to the Document")
         .expect("should have access to the Document")
 }
 }
 
 
-pub fn event_name_from_typ(typ: &str) -> &'static str {
+fn event_name_from_typ(typ: &str) -> &'static str {
     match typ {
     match typ {
         "copy" => "copy",
         "copy" => "copy",
         "cut" => "cut",
         "cut" => "cut",