mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-17 06:08:26 +00:00
polish: clean up the web module
This commit is contained in:
parent
1464d2e0a7
commit
823adc0834
15 changed files with 144 additions and 50 deletions
58
examples/weather_app.rs
Normal file
58
examples/weather_app.rs
Normal file
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
};
|
|
@ -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>,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// dioxus_web::launch(App, |c| c);
|
||||
/// }
|
||||
///
|
||||
///
|
||||
pub fn launch<F>(root: FC<()>, config: F)
|
||||
where
|
||||
F: FnOnce(WebConfig) -> WebConfig,
|
||||
{
|
||||
launch_with_props(root, (), config)
|
||||
/// 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);
|
||||
/// }
|
||||
///
|
||||
pub fn launch_with_props<T, F>(root: FC<T>, root_props: T, config: F)
|
||||
/// #[derive(ParitalEq, Props)]
|
||||
/// struct RootProps {
|
||||
/// name: String
|
||||
/// }
|
||||
///
|
||||
/// 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();
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<()>,
|
||||
|
|
Loading…
Add table
Reference in a new issue