polish: clean up the web module
This commit is contained in:
1 parent
1464d2e0a7
commit
823adc0834
15 files changed
+144
-50
No files matched your search
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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(
|
pub fn launch(
|
||||||
root: FC<()>,
|
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<()> {
|
) -> anyhow::Result<()> {
|
||||||
launch_with_props(root, (), builder)
|
launch_with_props(root, (), config_builder)
|
||||||
}
|
}
|
||||||
pub fn launch_with_props<P: Properties + 'static>(
|
pub fn launch_with_props<P: Properties + 'static>(
|
||||||
root: FC<P>,
|
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>,
|
cx: Context<'a>,
|
||||||
initial_state_fn: impl FnOnce() -> T,
|
initial_state_fn: impl FnOnce() -> T,
|
||||||
) -> UseState<'a, T> {
|
) -> UseState<'a, T> {
|
||||||
|
|||||||
@@ -1711,7 +1711,7 @@ impl select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl option {
|
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)
|
cx.attr("selected", val, None, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ static App: FC<()> = |cx, _| {
|
|||||||
h2 {"Add new client" margin_bottom: "10px" }
|
h2 {"Add new client" margin_bottom: "10px" }
|
||||||
form { class: "pure-form"
|
form { class: "pure-form"
|
||||||
input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
|
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}"
|
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}"
|
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" }
|
button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
|
||||||
@@ -83,7 +83,7 @@ static App: FC<()> = |cx, _| {
|
|||||||
}
|
}
|
||||||
Scene::Settings => {
|
Scene::Settings => {
|
||||||
rsx!(cx, div {
|
rsx!(cx, div {
|
||||||
h2 {"Settings" margin_bottom: "10px" }
|
h2 { "Settings" margin_bottom: "10px" }
|
||||||
button {
|
button {
|
||||||
background: "rgb(202, 60, 60)"
|
background: "rgb(202, 60, 60)"
|
||||||
class: "pure-button pure-button-primary"
|
class: "pure-button pure-button-primary"
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
/// This saves the decoding cost, making the interaction of Rust<->JS more performant.
|
/// 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.
|
/// 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.
|
/// Interning takes < 1ms at the start of the app, but saves a *ton* of time later on.
|
||||||
pub fn intern_cached_strings() {
|
///
|
||||||
|
/// Eventually we might want to procedurally generate these strings for common words, phrases, and values.
|
||||||
|
pub(crate) fn intern_cached_strings() {
|
||||||
let cached_words = [
|
let cached_words = [
|
||||||
// All the HTML Tags
|
// All the HTML Tags
|
||||||
"a",
|
"a",
|
||||||
|
|||||||
+15
-1
@@ -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 struct WebConfig {
|
||||||
pub(crate) hydrate: bool,
|
pub(crate) hydrate: bool,
|
||||||
pub(crate) rootname: String,
|
pub(crate) rootname: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WebConfig {
|
impl Default for WebConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -10,6 +21,7 @@ impl Default for WebConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebConfig {
|
impl WebConfig {
|
||||||
/// Enable SSR hydration
|
/// Enable SSR hydration
|
||||||
///
|
///
|
||||||
@@ -17,12 +29,14 @@ impl WebConfig {
|
|||||||
/// work and suspended nodes.
|
/// work and suspended nodes.
|
||||||
///
|
///
|
||||||
/// Dioxus will load up all the elements with the `dio_el` data attribute into memory when the page is loaded.
|
/// 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 {
|
pub fn hydrate(mut self, f: bool) -> Self {
|
||||||
self.hydrate = f;
|
self.hydrate = f;
|
||||||
self
|
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 {
|
pub fn rootname(mut self, name: impl Into<String>) -> Self {
|
||||||
self.rootname = name.into();
|
self.rootname = name.into();
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
|
|
||||||
|
|
||||||
use dioxus_core::{
|
use dioxus_core::{
|
||||||
events::{on::GenericEventInner, SyntheticEvent, UserEvent},
|
events::{SyntheticEvent, UserEvent},
|
||||||
mutations::NodeRefMutation,
|
mutations::NodeRefMutation,
|
||||||
scheduler::SchedulerMsg,
|
scheduler::SchedulerMsg,
|
||||||
DomEdit, ElementId, ScopeId,
|
DomEdit, ElementId, ScopeId,
|
||||||
};
|
};
|
||||||
use fxhash::FxHashMap;
|
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::{
|
use web_sys::{
|
||||||
window, Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
|
Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
|
||||||
HtmlOptionElement, HtmlTextAreaElement, Node, NodeList, UiEvent,
|
HtmlOptionElement, HtmlTextAreaElement, Node, NodeList,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{nodeslab::NodeSlab, WebConfig};
|
use crate::{nodeslab::NodeSlab, WebConfig};
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
//! Ported events into Dioxus Synthetic Event system
|
//! Ported events into Dioxus Synthetic Event system
|
||||||
//!
|
|
||||||
//! event porting is pretty boring, sorry.
|
|
||||||
|
|
||||||
use dioxus_core::events::on::*;
|
use dioxus_core::events::on::*;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::{Event, UiEvent};
|
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 {
|
trait WebsysGenericEvent {
|
||||||
fn as_ui_event(&self) -> &UiEvent;
|
fn as_ui_event(&self) -> &UiEvent;
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-19
@@ -70,19 +70,28 @@ mod events;
|
|||||||
mod nodeslab;
|
mod nodeslab;
|
||||||
mod ric_raf;
|
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
|
/// # Example
|
||||||
///
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn main() {
|
||||||
|
/// dioxus_web::launch(App, |c| c);
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
///
|
/// static App: FC<()> = |cx, props| {
|
||||||
pub fn launch<F>(root: FC<()>, config: F)
|
/// rsx!(cx, div {"hello world"})
|
||||||
where
|
/// }
|
||||||
F: FnOnce(WebConfig) -> WebConfig,
|
/// ```
|
||||||
{
|
pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> WebConfig) {
|
||||||
launch_with_props(root, (), config)
|
launch_with_props(root_component, (), configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Launches the VirtualDOM from the specified component function and props.
|
/// Launches the VirtualDOM from the specified component function and props.
|
||||||
@@ -91,28 +100,41 @@ where
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # 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
|
where
|
||||||
T: Properties + 'static,
|
T: Properties + 'static,
|
||||||
F: FnOnce(WebConfig) -> WebConfig,
|
F: FnOnce(WebConfig) -> WebConfig,
|
||||||
{
|
{
|
||||||
let config = config(WebConfig::default());
|
let config = configuration_builder(WebConfig::default());
|
||||||
wasm_bindgen_futures::spawn_local(run_with_props(root, root_props, config));
|
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
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// fn main() {
|
/// 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) {
|
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);
|
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 {
|
if !should_hydrate {
|
||||||
log::info!("Applying rebuild edits..., {:?}", mutations);
|
log::info!("Applying rebuild edits..., {:?}", mutations);
|
||||||
websys_dom.process_edits(&mut mutations.edits);
|
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();
|
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;
|
use web_sys::Node;
|
||||||
|
|
||||||
pub struct NodeSlab {
|
pub(crate) struct NodeSlab {
|
||||||
nodes: Vec<Option<Node>>,
|
nodes: Vec<Option<Node>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeSlab {
|
impl NodeSlab {
|
||||||
pub fn new(capacity: usize) -> NodeSlab {
|
pub fn new(capacity: usize) -> NodeSlab {
|
||||||
let mut nodes = Vec::with_capacity(capacity);
|
let nodes = Vec::with_capacity(capacity);
|
||||||
for x in 0..5 {
|
|
||||||
nodes.push(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeSlab { nodes }
|
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 gloo_timers::future::TimeoutFuture;
|
||||||
use js_sys::Function;
|
use js_sys::Function;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
|
||||||
use wasm_bindgen::{prelude::Closure, JsValue};
|
|
||||||
use web_sys::{window, Window};
|
use web_sys::{window, Window};
|
||||||
|
|
||||||
pub struct RafLoop {
|
pub(crate) struct RafLoop {
|
||||||
window: Window,
|
window: Window,
|
||||||
ric_receiver: async_channel::Receiver<u32>,
|
ric_receiver: async_channel::Receiver<u32>,
|
||||||
raf_receiver: async_channel::Receiver<()>,
|
raf_receiver: async_channel::Receiver<()>,
|
||||||
|
|||||||
Reference in new issue
Block a user