Browse Source

polish: clean up the web module

Jonathan Kelley 3 năm trước cách đây
mục cha
commit
823adc0834

+ 0 - 0
examples/examples/calculator.rs → examples/_examples/calculator_.rs


+ 0 - 0
examples/examples/demo.rs → examples/_examples/demo.rs


+ 0 - 0
examples/examples/hifive.rs → examples/_examples/hifive.rs


+ 58 - 0
examples/weather_app.rs

@@ -0,0 +1,58 @@
+//! Example: Weather App
+//! --------------------
+//!
+//!
+//!
+
+use dioxus::prelude::*;
+
+fn main() {
+    // dioxus::desktop::launch(App, |c| c);
+}
+
+static App: FC<()> = |cx, props| {
+    //
+    let body = use_suspense(
+        cx,
+        || async {
+            //
+        },
+        |cx, props| {
+            //
+            rsx!(cx, WeatherDisplay {})
+        },
+    );
+
+    rsx!(cx, div {
+        {body}
+    })
+};
+
+#[derive(PartialEq, Props)]
+struct WeatherProps {}
+
+static WeatherDisplay: FC<WeatherProps> = |cx, props| {
+    //
+    cx.render(rsx!(
+        div { class: "flex items-center justify-center flex-col"
+            div { class: "flex items-center justify-center"
+                div { class: "flex flex-col bg-white rounded p-4 w-full max-w-xs"
+                    div{ class: "font-bold text-xl"
+                        "Jon's awesome site!!"
+                    }
+                    div{ class: "text-sm text-gray-500"
+                        "He worked so hard on it :)"
+                    }
+                    div { class: "flex flex-row items-center justify-center mt-6"
+                        div { class: "font-medium text-6xl"
+                            "1337"
+                        }
+                    }
+                    div { class: "flex flex-row justify-between mt-6"
+                        "Legit made my own React"
+                    }
+                }
+            }
+        }
+    ))
+};

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

@@ -27,9 +27,9 @@ static HTML_CONTENT: &'static str = include_str!("./index.html");
 
 pub fn launch(
     root: FC<()>,
-    builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
+    config_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
 ) -> anyhow::Result<()> {
-    launch_with_props(root, (), builder)
+    launch_with_props(root, (), config_builder)
 }
 pub fn launch_with_props<P: Properties + 'static>(
     root: FC<P>,

+ 1 - 1
packages/hooks/src/usestate.rs

@@ -49,7 +49,7 @@ use std::{
 ///     }
 /// }
 /// ```
-pub fn use_state<'a, 'c, T: 'static>(
+pub fn use_state<'a, T: 'static>(
     cx: Context<'a>,
     initial_state_fn: impl FnOnce() -> T,
 ) -> UseState<'a, T> {

+ 1 - 1
packages/html/src/lib.rs

@@ -1711,7 +1711,7 @@ impl select {
 }
 
 impl option {
-    fn selected<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
+    pub fn selected<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
         cx.attr("selected", val, None, true)
     }
 }

+ 4 - 4
packages/web/examples/crm2.rs

@@ -68,13 +68,13 @@ static App: FC<()> = |cx, _| {
                 h2 {"Add new client" margin_bottom: "10px" }
                 form { class: "pure-form"
                     input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
-                        oninput: move |e| firstname.set(e.value())
+                        oninput: move |evt| firstname.set(evt.value())
                     }
                     input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
-                        oninput: move |e| lastname.set(e.value())
+                        oninput: move |evt| lastname.set(evt.value())
                     }
                     textarea { class: "new-client description" placeholder: "Description" value: "{description}"
-                        oninput: move |e| description.set(e.value())
+                        oninput: move |evt| description.set(evt.value())
                     }
                 }
                 button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
@@ -83,7 +83,7 @@ static App: FC<()> = |cx, _| {
         }
         Scene::Settings => {
             rsx!(cx, div {
-                h2 {"Settings" margin_bottom: "10px" }
+                h2 { "Settings" margin_bottom: "10px" }
                 button {
                     background: "rgb(202, 60, 60)"
                     class: "pure-button pure-button-primary"

+ 4 - 2
packages/web/src/cache.rs

@@ -2,8 +2,10 @@
 /// This saves the decoding cost, making the interaction of Rust<->JS more performant.
 /// We intern all the HTML tags and attributes, making most operations much faster.
 ///
-/// Interning takes about 1ms at the start of the app, but saves a *ton* of time later on.
-pub fn intern_cached_strings() {
+/// Interning takes < 1ms at the start of the app, but saves a *ton* of time later on.
+///
+/// Eventually we might want to procedurally generate these strings for common words, phrases, and values.
+pub(crate) fn intern_cached_strings() {
     let cached_words = [
         // All the HTML Tags
         "a",

+ 15 - 1
packages/web/src/cfg.rs

@@ -1,7 +1,18 @@
+///  Configuration for the WebSys renderer for the Dioxus VirtualDOM.
+///
+/// This struct helps configure the specifics of hydration and render destination for WebSys.
+///
+/// # Example
+/// ```rust, ignore
+/// fn main() {
+///     dioxus::web::launch(App, |cfg| cfg.hydrate(true).root_name("myroot"))
+/// }
+/// ```
 pub struct WebConfig {
     pub(crate) hydrate: bool,
     pub(crate) rootname: String,
 }
+
 impl Default for WebConfig {
     fn default() -> Self {
         Self {
@@ -10,6 +21,7 @@ impl Default for WebConfig {
         }
     }
 }
+
 impl WebConfig {
     /// Enable SSR hydration
     ///
@@ -17,12 +29,14 @@ impl WebConfig {
     /// work and suspended nodes.
     ///
     /// Dioxus will load up all the elements with the `dio_el` data attribute into memory when the page is loaded.
-    ///
     pub fn hydrate(mut self, f: bool) -> Self {
         self.hydrate = f;
         self
     }
 
+    /// Set the name of the element that Dioxus will use as the root.
+    ///
+    /// This is akint to calling React.render() on the element with the specified name.
     pub fn rootname(mut self, name: impl Into<String>) -> Self {
         self.rootname = name.into();
         self

+ 5 - 6
packages/web/src/dom.rs

@@ -1,16 +1,15 @@
-use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
-
 use dioxus_core::{
-    events::{on::GenericEventInner, SyntheticEvent, UserEvent},
+    events::{SyntheticEvent, UserEvent},
     mutations::NodeRefMutation,
     scheduler::SchedulerMsg,
     DomEdit, ElementId, ScopeId,
 };
 use fxhash::FxHashMap;
-use wasm_bindgen::{closure::Closure, JsCast, JsValue};
+use std::{fmt::Debug, rc::Rc};
+use wasm_bindgen::{closure::Closure, JsCast};
 use web_sys::{
-    window, Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
-    HtmlOptionElement, HtmlTextAreaElement, Node, NodeList, UiEvent,
+    Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
+    HtmlOptionElement, HtmlTextAreaElement, Node, NodeList,
 };
 
 use crate::{nodeslab::NodeSlab, WebConfig};

+ 1 - 3
packages/web/src/events.rs

@@ -1,12 +1,10 @@
 //! Ported events into Dioxus Synthetic Event system
-//!
-//! event porting is pretty boring, sorry.
 
 use dioxus_core::events::on::*;
 use wasm_bindgen::JsCast;
 use web_sys::{Event, UiEvent};
 
-/// All events implement the generic event type - they're all UI events
+/// All events implement the generic event type - they're all `UI events`
 trait WebsysGenericEvent {
     fn as_ui_event(&self) -> &UiEvent;
 }

+ 39 - 19
packages/web/src/lib.rs

@@ -70,19 +70,28 @@ mod events;
 mod nodeslab;
 mod ric_raf;
 
-/// Launches the VirtualDOM from the specified component function.
+/// Launch the VirtualDOM given a root component and a configuration.
 ///
-/// This method will block the thread with `spawn_local`
+/// This function expects the root component to not have root props. To launch the root component with root props, use
+/// `launch_with_props` instead.
 ///
-/// # Example
+/// This method will block the thread with `spawn_local` from wasm_bindgen_futures.
 ///
+/// If you need to run the VirtualDOM in its own thread, use `run_with_props` instead and await the future.
 ///
+/// # Example
 ///
-pub fn launch<F>(root: FC<()>, config: F)
-where
-    F: FnOnce(WebConfig) -> WebConfig,
-{
-    launch_with_props(root, (), config)
+/// ```rust
+/// fn main() {
+///     dioxus_web::launch(App, |c| c);
+/// }
+///
+/// static App: FC<()> = |cx, props| {
+///     rsx!(cx, div {"hello world"})
+/// }
+/// ```
+pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> WebConfig) {
+    launch_with_props(root_component, (), configuration)
 }
 
 /// Launches the VirtualDOM from the specified component function and props.
@@ -91,28 +100,41 @@ where
 ///
 /// # Example
 ///
+/// ```rust
+/// fn main() {
+///     dioxus_web::launch_with_props(App, RootProps { name: String::from("joe") }, |c| c);
+/// }
+///
+/// #[derive(ParitalEq, Props)]
+/// struct RootProps {
+///     name: String
+/// }
 ///
-pub fn launch_with_props<T, F>(root: FC<T>, root_props: T, config: F)
+/// static App: FC<RootProps> = |cx, props| {
+///     rsx!(cx, div {"hello {props.name}"})
+/// }
+/// ```
+pub fn launch_with_props<T, F>(root_component: FC<T>, root_properties: T, configuration_builder: F)
 where
     T: Properties + 'static,
     F: FnOnce(WebConfig) -> WebConfig,
 {
-    let config = config(WebConfig::default());
-    wasm_bindgen_futures::spawn_local(run_with_props(root, root_props, config));
+    let config = configuration_builder(WebConfig::default());
+    wasm_bindgen_futures::spawn_local(run_with_props(root_component, root_properties, config));
 }
-/// This method is the primary entrypoint for Websys Dioxus apps. Will panic if an error occurs while rendering.
-/// See DioxusErrors for more information on how these errors could occour.
+
+/// Runs the app as a future that can be scheduled around the main thread.
+///
+/// Polls futures internal to the VirtualDOM, hence the async nature of this function.
 ///
 /// # Example
 ///
 /// ```ignore
 /// fn main() {
-///     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
+///     let app_fut = dioxus_web::run_with_props(App, RootProps { name: String::from("joe") }, |c| c);
+///     wasm_bindgen_futures::spawn_local(app_fut);
 /// }
 /// ```
-///
-/// Run the app to completion, panicing if any error occurs while rendering.
-/// Pairs well with the wasm_bindgen async handler
 pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T, cfg: WebConfig) {
     let mut dom = VirtualDom::new_with_props(root, root_props);
 
@@ -135,8 +157,6 @@ pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T,
     if !should_hydrate {
         log::info!("Applying rebuild edits..., {:?}", mutations);
         websys_dom.process_edits(&mut mutations.edits);
-    } else {
-        // websys dom processed the config and hydrated the dom already
     }
 
     let work_loop = ric_raf::RafLoop::new();

+ 4 - 7
packages/web/src/nodeslab.rs

@@ -1,18 +1,15 @@
-use std::ops::{Index, IndexMut};
+//! This module provides a mirror of the VirtualDOM Element Slab using a Vector.
 
+use std::ops::{Index, IndexMut};
 use web_sys::Node;
 
-pub struct NodeSlab {
+pub(crate) struct NodeSlab {
     nodes: Vec<Option<Node>>,
 }
 
 impl NodeSlab {
     pub fn new(capacity: usize) -> NodeSlab {
-        let mut nodes = Vec::with_capacity(capacity);
-        for x in 0..5 {
-            nodes.push(None);
-        }
-
+        let nodes = Vec::with_capacity(capacity);
         NodeSlab { nodes }
     }
 }

+ 10 - 4
packages/web/src/ric_raf.rs

@@ -1,12 +1,18 @@
-//! RequestAnimationFrame and RequestIdleCallback port and polyfill.
+//! This module provides some utilities around scheduling tasks on the main thread of the browser.
+//!
+//! The ultimate goal here is to not block the main thread during animation frames, so our animations don't result in "jank".
+//!
+//! Hence, this module provides Dioxus "Jank Free Rendering" on the web.
+//!
+//! Because RIC doesn't work on Safari, we polyfill using the "ricpolyfill.js" file and use some basic detection to see
+//! if RIC is available.
 
 use gloo_timers::future::TimeoutFuture;
 use js_sys::Function;
-use wasm_bindgen::JsCast;
-use wasm_bindgen::{prelude::Closure, JsValue};
+use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
 use web_sys::{window, Window};
 
-pub struct RafLoop {
+pub(crate) struct RafLoop {
     window: Window,
     ric_receiver: async_channel::Receiver<u32>,
     raf_receiver: async_channel::Receiver<()>,