mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
wip: rename fc to component
This commit is contained in:
parent
85ab8b91c6
commit
1e4a599d14
61 changed files with 524 additions and 145 deletions
|
@ -17,6 +17,7 @@ dioxus-desktop = { path = "./packages/desktop", optional = true }
|
||||||
dioxus-hooks = { path = "./packages/hooks", optional = true }
|
dioxus-hooks = { path = "./packages/hooks", optional = true }
|
||||||
dioxus-ssr = { path = "./packages/ssr", optional = true }
|
dioxus-ssr = { path = "./packages/ssr", optional = true }
|
||||||
dioxus-mobile = { path = "./packages/mobile", optional = true }
|
dioxus-mobile = { path = "./packages/mobile", optional = true }
|
||||||
|
dioxus-liveview = { path = "./packages/liveview", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# core
|
# core
|
||||||
|
@ -26,6 +27,7 @@ macro = ["dioxus-core-macro"]
|
||||||
hooks = ["dioxus-hooks"]
|
hooks = ["dioxus-hooks"]
|
||||||
html = ["dioxus-html"]
|
html = ["dioxus-html"]
|
||||||
router = ["dioxus-router"]
|
router = ["dioxus-router"]
|
||||||
|
liveview = ["dioxus-liveview"]
|
||||||
|
|
||||||
# utilities
|
# utilities
|
||||||
atoms = []
|
atoms = []
|
||||||
|
|
|
@ -11,7 +11,7 @@ async fn main() {
|
||||||
dioxus::desktop::launch(App, |c| c);
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static App: FC<()> = |cx, _| {
|
pub static App: Component<()> = |cx, _| {
|
||||||
let count = use_state(cx, || 0);
|
let count = use_state(cx, || 0);
|
||||||
let mut direction = use_state(cx, || 1);
|
let mut direction = use_state(cx, || 1);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn main() {
|
||||||
dioxus::desktop::launch(APP, |cfg| cfg);
|
dioxus::desktop::launch(APP, |cfg| cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: FC<()> = |cx, _| {
|
const APP: Component<()> = |cx, _| {
|
||||||
let cur_val = use_state(cx, || 0.0_f64);
|
let cur_val = use_state(cx, || 0.0_f64);
|
||||||
let operator = use_state(cx, || None as Option<&'static str>);
|
let operator = use_state(cx, || None as Option<&'static str>);
|
||||||
let display_value = use_state(cx, || String::from(""));
|
let display_value = use_state(cx, || String::from(""));
|
||||||
|
|
|
@ -27,7 +27,7 @@ fn main() {
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let p1 = use_state(cx, || 0);
|
let p1 = use_state(cx, || 0);
|
||||||
let p2 = use_state(cx, || 0);
|
let p2 = use_state(cx, || 0);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub struct Client {
|
||||||
pub description: String,
|
pub description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let mut clients = use_ref(cx, || vec![] as Vec<Client>);
|
let mut clients = use_ref(cx, || vec![] as Vec<Client>);
|
||||||
let mut scene = use_state(cx, || Scene::ClientsList);
|
let mut scene = use_state(cx, || Scene::ClientsList);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ fn main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let file_manager = use_ref(cx, || Files::new());
|
let file_manager = use_ref(cx, || Files::new());
|
||||||
let files = file_manager.read();
|
let files = file_manager.read();
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, _props| {
|
static App: Component<()> = |cx, _props| {
|
||||||
let mut items = use_ref(cx, || vec![]);
|
let mut items = use_ref(cx, || vec![]);
|
||||||
let mut selected = use_state(cx, || None);
|
let mut selected = use_state(cx, || None);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ fn main() {
|
||||||
dioxus::desktop::launch(App, |c| c.with_prerendered(content));
|
dioxus::desktop::launch(App, |c| c.with_prerendered(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut val = use_state(cx, || 0);
|
let mut val = use_state(cx, || 0);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
|
|
@ -36,7 +36,7 @@ fn main() {
|
||||||
dioxus_desktop::run(APP, (), |c| c.with_edits(edits));
|
dioxus_desktop::run(APP, (), |c| c.with_edits(edits));
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP: FC<()> = |(cx, _props)| {
|
const APP: Component<()> = |(cx, _props)| {
|
||||||
rsx!(cx, div {
|
rsx!(cx, div {
|
||||||
"some app"
|
"some app"
|
||||||
})
|
})
|
||||||
|
|
|
@ -31,7 +31,7 @@ fn main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let state = use_ref(cx, || Calculator::new());
|
let state = use_ref(cx, || Calculator::new());
|
||||||
|
|
||||||
let clear_display = state.read().display_value.eq("0");
|
let clear_display = state.read().display_value.eq("0");
|
||||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
||||||
dioxus::desktop::launch(App, |c| c);
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static App: FC<()> = |cx, _| {
|
pub static App: Component<()> = |cx, _| {
|
||||||
let state = use_state(cx, PlayerState::new);
|
let state = use_state(cx, PlayerState::new);
|
||||||
|
|
||||||
let is_playing = state.is_playing();
|
let is_playing = state.is_playing();
|
||||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
||||||
dioxus::desktop::launch(App, |c| c);
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut count = use_state(cx, || 0);
|
let mut count = use_state(cx, || 0);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub enum Route {
|
||||||
NotFound,
|
NotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let route = use_router(cx, Route::parse)?;
|
let route = use_router(cx, Route::parse)?;
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
|
|
@ -49,7 +49,7 @@ const NONE_ELEMENT: Option<()> = None;
|
||||||
use baller::Baller;
|
use baller::Baller;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
pub static Example: FC<()> = |cx, props| {
|
pub static Example: Component<()> = |cx, props| {
|
||||||
let formatting = "formatting!";
|
let formatting = "formatting!";
|
||||||
let formatting_tuple = ("a", "b");
|
let formatting_tuple = ("a", "b");
|
||||||
let lazy_fmt = format_args!("lazily formatted text");
|
let lazy_fmt = format_args!("lazily formatted text");
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
||||||
println!("{}", ssr::render_vdom(&vdom, |c| c));
|
println!("{}", ssr::render_vdom(&vdom, |c| c));
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div {
|
div {
|
||||||
h1 { "Title" }
|
h1 { "Title" }
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
||||||
|
|
||||||
const STYLE: &str = "body {overflow:hidden;}";
|
const STYLE: &str = "body {overflow:hidden;}";
|
||||||
|
|
||||||
pub static App: FC<()> = |cx, props| {
|
pub static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div { class: "overflow-hidden"
|
div { class: "overflow-hidden"
|
||||||
style { "{STYLE}" }
|
style { "{STYLE}" }
|
||||||
|
@ -30,7 +30,7 @@ pub static App: FC<()> = |cx, props| {
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static Header: FC<()> = |cx, props| {
|
pub static Header: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
header { class: "text-gray-400 bg-gray-900 body-font"
|
header { class: "text-gray-400 bg-gray-900 body-font"
|
||||||
|
@ -56,7 +56,7 @@ pub static Header: FC<()> = |cx, props| {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static Hero: FC<()> = |cx, props| {
|
pub static Hero: Component<()> = |cx, props| {
|
||||||
//
|
//
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||||
|
@ -94,7 +94,7 @@ pub static Hero: FC<()> = |cx, props| {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
pub static Entry: FC<()> = |cx, props| {
|
pub static Entry: Component<()> = |cx, props| {
|
||||||
//
|
//
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||||
|
@ -107,7 +107,7 @@ pub static Entry: FC<()> = |cx, props| {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static StacksIcon: FC<()> = |cx, props| {
|
pub static StacksIcon: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
svg {
|
svg {
|
||||||
// xmlns: "http://www.w3.org/2000/svg"
|
// xmlns: "http://www.w3.org/2000/svg"
|
||||||
|
@ -122,7 +122,7 @@ pub static StacksIcon: FC<()> = |cx, props| {
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
pub static RightArrowIcon: FC<()> = |cx, props| {
|
pub static RightArrowIcon: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
svg {
|
svg {
|
||||||
fill: "none"
|
fill: "none"
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
||||||
dioxus::desktop::launch(App, |c| c);
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut count = use_state(cx, || 0);
|
let mut count = use_state(cx, || 0);
|
||||||
|
|
||||||
cx.push_task(async move {
|
cx.push_task(async move {
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub struct TodoItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
const STYLE: &str = include_str!("./assets/todomvc.css");
|
const STYLE: &str = include_str!("./assets/todomvc.css");
|
||||||
const App: FC<()> = |cx, props| {
|
const App: Component<()> = |cx, props| {
|
||||||
let mut draft = use_state(cx, || "".to_string());
|
let mut draft = use_state(cx, || "".to_string());
|
||||||
let mut todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
|
let mut todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
|
||||||
let mut filter = use_state(cx, || FilterState::All);
|
let mut filter = use_state(cx, || FilterState::All);
|
||||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
||||||
|
|
||||||
const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather";
|
const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather";
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
//
|
//
|
||||||
let body = use_suspense(
|
let body = use_suspense(
|
||||||
cx,
|
cx,
|
||||||
|
@ -40,7 +40,7 @@ static App: FC<()> = |cx, props| {
|
||||||
#[derive(PartialEq, Props)]
|
#[derive(PartialEq, Props)]
|
||||||
struct WeatherProps {}
|
struct WeatherProps {}
|
||||||
|
|
||||||
static WeatherDisplay: FC<WeatherProps> = |cx, props| {
|
static WeatherDisplay: Component<WeatherProps> = |cx, props| {
|
||||||
//
|
//
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div { class: "flex items-center justify-center flex-col"
|
div { class: "flex items-center justify-center flex-col"
|
||||||
|
|
|
@ -19,7 +19,7 @@ fn main() {
|
||||||
dioxus::web::launch(App, |c| c);
|
dioxus::web::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut rng = SmallRng::from_entropy();
|
let mut rng = SmallRng::from_entropy();
|
||||||
let rows = (0..1_000).map(|f| {
|
let rows = (0..1_000).map(|f| {
|
||||||
let label = Label::new(&mut rng);
|
let label = Label::new(&mut rng);
|
||||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
||||||
dioxus::web::launch(App, |c| c);
|
dioxus::web::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut count = use_state(cx, || 0);
|
let mut count = use_state(cx, || 0);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
|
|
@ -23,7 +23,7 @@ criterion_group!(mbenches, create_rows);
|
||||||
criterion_main!(mbenches);
|
criterion_main!(mbenches);
|
||||||
|
|
||||||
fn create_rows(c: &mut Criterion) {
|
fn create_rows(c: &mut Criterion) {
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let mut rng = SmallRng::from_entropy();
|
let mut rng = SmallRng::from_entropy();
|
||||||
let rows = (0..10_000_usize).map(|f| {
|
let rows = (0..10_000_usize).map(|f| {
|
||||||
let label = Label::new(&mut rng);
|
let label = Label::new(&mut rng);
|
||||||
|
|
34
packages/core/examples/handler_thru_props.rs
Normal file
34
packages/core/examples/handler_thru_props.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_core as dioxus;
|
||||||
|
use dioxus_core_macro::*;
|
||||||
|
use dioxus_html as dioxus_elements;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = VirtualDom::new(App);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn App(cx: Context, _props: &()) -> Element {
|
||||||
|
//
|
||||||
|
cx.render(rsx!(
|
||||||
|
div {
|
||||||
|
Child {}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ChildProps<'a> {
|
||||||
|
click_handler: EventHandler<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Child(cx: Context, _props: &()) -> Element {
|
||||||
|
//
|
||||||
|
cx.render(rsx!(
|
||||||
|
div {
|
||||||
|
h1 {
|
||||||
|
"Hello, World!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ use dioxus_html as dioxus_elements;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let mut rng = SmallRng::from_entropy();
|
let mut rng = SmallRng::from_entropy();
|
||||||
let rows = (0..10_000_usize).map(|f| {
|
let rows = (0..10_000_usize).map(|f| {
|
||||||
let label = Label::new(&mut rng);
|
let label = Label::new(&mut rng);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_core as dioxus;
|
use dioxus_core as dioxus;
|
||||||
use dioxus_core_macro::*;
|
use dioxus_core_macro::*;
|
||||||
|
@ -7,8 +9,8 @@ fn main() {
|
||||||
let _ = VirtualDom::new(Parent);
|
let _ = VirtualDom::new(Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Parent(cx: Context, props: &()) -> Element {
|
fn Parent(cx: Context, _props: &()) -> Element {
|
||||||
let value = cx.use_hook(|_| String::new(), |f| &*f);
|
let value = cx.use_hook(|_| String::new(), |f| f);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
|
|
@ -32,19 +32,21 @@ pub(crate) mod innerlude {
|
||||||
pub use crate::virtual_dom::*;
|
pub use crate::virtual_dom::*;
|
||||||
|
|
||||||
pub type Element = Option<VPortal>;
|
pub type Element = Option<VPortal>;
|
||||||
pub type FC<P> = for<'a> fn(Context<'a>, &'a P) -> Element;
|
pub type Component<P> = for<'a> fn(Context<'a>, &'a P) -> Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::innerlude::{
|
pub use crate::innerlude::{
|
||||||
Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, IntoVNode,
|
Attribute, Component, Context, DioxusElement, DomEdit, Element, ElementId, EventHandler,
|
||||||
LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId,
|
EventPriority, IntoVNode, LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties,
|
||||||
UserEvent, VElement, VFragment, VNode, VirtualDom, FC,
|
SchedulerMsg, ScopeId, UserEvent, VElement, VFragment, VNode, VirtualDom,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::component::{fc_to_builder, Fragment, Properties};
|
pub use crate::component::{fc_to_builder, Fragment, Properties};
|
||||||
pub use crate::innerlude::Context;
|
pub use crate::innerlude::Context;
|
||||||
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, NodeFactory, Scope, FC};
|
pub use crate::innerlude::{
|
||||||
|
Component, DioxusElement, Element, EventHandler, LazyNodes, NodeFactory, Scope,
|
||||||
|
};
|
||||||
pub use crate::nodes::VNode;
|
pub use crate::nodes::VNode;
|
||||||
pub use crate::VirtualDom;
|
pub use crate::VirtualDom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,9 +338,32 @@ pub struct Listener<'bump> {
|
||||||
pub event: &'static str,
|
pub event: &'static str,
|
||||||
|
|
||||||
/// The actual callback that the user specified
|
/// The actual callback that the user specified
|
||||||
#[allow(clippy::type_complexity)]
|
pub(crate) callback: EventHandler<'bump>,
|
||||||
pub(crate) callback:
|
}
|
||||||
RefCell<Option<BumpBox<'bump, dyn FnMut(std::sync::Arc<dyn Any + Send + Sync>) + 'bump>>>,
|
|
||||||
|
pub struct EventHandler<'bump> {
|
||||||
|
pub callback: &'bump RefCell<Option<ListenerCallback<'bump>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventHandler<'_> {
|
||||||
|
pub fn call(&self, event: Arc<dyn Any + Send + Sync>) {
|
||||||
|
if let Some(callback) = self.callback.borrow_mut().as_mut() {
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn release(&self) {
|
||||||
|
self.callback.replace(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type ListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(Arc<dyn Any + Send + Sync>) + 'bump>;
|
||||||
|
|
||||||
|
impl Copy for EventHandler<'_> {}
|
||||||
|
impl Clone for EventHandler<'_> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
callback: self.callback,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A cached node is a "pointer" to a "rendered" node in a particular scope
|
/// A cached node is a "pointer" to a "rendered" node in a particular scope
|
||||||
|
@ -608,15 +631,11 @@ impl<'a> NodeFactory<'a> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listener(
|
pub fn listener(self, event: &'static str, callback: EventHandler<'a>) -> Listener<'a> {
|
||||||
self,
|
|
||||||
event: &'static str,
|
|
||||||
callback: BumpBox<'a, dyn FnMut(Arc<dyn Any + Send + Sync>) + 'a>,
|
|
||||||
) -> Listener<'a> {
|
|
||||||
Listener {
|
Listener {
|
||||||
event,
|
event,
|
||||||
mounted_node: Cell::new(None),
|
mounted_node: Cell::new(None),
|
||||||
callback: RefCell::new(Some(callback)),
|
callback,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,6 +274,7 @@ impl Scope {
|
||||||
let mut search_parent = self.parent_scope;
|
let mut search_parent = self.parent_scope;
|
||||||
|
|
||||||
while let Some(parent_ptr) = search_parent {
|
while let Some(parent_ptr) = search_parent {
|
||||||
|
// safety: all parent pointers are valid thanks to the bump arena
|
||||||
let parent = unsafe { &*parent_ptr };
|
let parent = unsafe { &*parent_ptr };
|
||||||
if let Some(shared) = parent.shared_contexts.borrow().get(&TypeId::of::<T>()) {
|
if let Some(shared) = parent.shared_contexts.borrow().get(&TypeId::of::<T>()) {
|
||||||
return Some(shared.clone().downcast::<T>().unwrap());
|
return Some(shared.clone().downcast::<T>().unwrap());
|
||||||
|
|
|
@ -281,30 +281,30 @@ impl ScopeArena {
|
||||||
/// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will
|
/// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will
|
||||||
/// be dropped.
|
/// be dropped.
|
||||||
pub(crate) fn ensure_drop_safety(&self, scope_id: &ScopeId) {
|
pub(crate) fn ensure_drop_safety(&self, scope_id: &ScopeId) {
|
||||||
let scope = self.get_scope(scope_id).unwrap();
|
if let Some(scope) = self.get_scope(scope_id) {
|
||||||
|
let mut items = scope.items.borrow_mut();
|
||||||
|
|
||||||
let mut items = scope.items.borrow_mut();
|
// make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
|
||||||
|
// run the hooks (which hold an &mut Reference)
|
||||||
|
// recursively call ensure_drop_safety on all children
|
||||||
|
items.borrowed_props.drain(..).for_each(|comp| {
|
||||||
|
let scope_id = comp
|
||||||
|
.associated_scope
|
||||||
|
.get()
|
||||||
|
.expect("VComponents should be associated with a valid Scope");
|
||||||
|
|
||||||
// make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
|
self.ensure_drop_safety(&scope_id);
|
||||||
// run the hooks (which hold an &mut Reference)
|
|
||||||
// recursively call ensure_drop_safety on all children
|
|
||||||
items.borrowed_props.drain(..).for_each(|comp| {
|
|
||||||
let scope_id = comp
|
|
||||||
.associated_scope
|
|
||||||
.get()
|
|
||||||
.expect("VComponents should be associated with a valid Scope");
|
|
||||||
|
|
||||||
self.ensure_drop_safety(&scope_id);
|
let mut drop_props = comp.drop_props.borrow_mut().take().unwrap();
|
||||||
|
drop_props();
|
||||||
|
});
|
||||||
|
|
||||||
let mut drop_props = comp.drop_props.borrow_mut().take().unwrap();
|
// Now that all the references are gone, we can safely drop our own references in our listeners.
|
||||||
drop_props();
|
items
|
||||||
});
|
.listeners
|
||||||
|
.drain(..)
|
||||||
// Now that all the references are gone, we can safely drop our own references in our listeners.
|
.for_each(|listener| drop(listener.callback.callback.borrow_mut().take()));
|
||||||
items
|
}
|
||||||
.listeners
|
|
||||||
.drain(..)
|
|
||||||
.for_each(|listener| drop(listener.callback.borrow_mut().take()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run_scope(&self, id: &ScopeId) -> bool {
|
pub(crate) fn run_scope(&self, id: &ScopeId) -> bool {
|
||||||
|
@ -375,7 +375,7 @@ impl ScopeArena {
|
||||||
//
|
//
|
||||||
for listener in real_el.listeners.borrow().iter() {
|
for listener in real_el.listeners.borrow().iter() {
|
||||||
if listener.event == event.name {
|
if listener.event == event.name {
|
||||||
let mut cb = listener.callback.borrow_mut();
|
let mut cb = listener.callback.callback.borrow_mut();
|
||||||
if let Some(cb) = cb.as_mut() {
|
if let Some(cb) = cb.as_mut() {
|
||||||
(cb)(event.data.clone());
|
(cb)(event.data.clone());
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ impl VirtualDom {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note: the VirtualDOM is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
|
/// Note: the VirtualDOM is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
|
||||||
pub fn new(root: FC<()>) -> Self {
|
pub fn new(root: Component<()>) -> Self {
|
||||||
Self::new_with_props(root, ())
|
Self::new_with_props(root, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ impl VirtualDom {
|
||||||
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
|
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
|
||||||
/// let mutations = dom.rebuild();
|
/// let mutations = dom.rebuild();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new_with_props<P: 'static>(root: FC<P>, root_props: P) -> Self {
|
pub fn new_with_props<P: 'static>(root: Component<P>, root_props: P) -> Self {
|
||||||
let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
|
let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
|
||||||
Self::new_with_props_and_scheduler(root, root_props, sender, receiver)
|
Self::new_with_props_and_scheduler(root, root_props, sender, receiver)
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ impl VirtualDom {
|
||||||
/// This is useful when the VirtualDom must be driven from outside a thread and it doesn't make sense to wait for the
|
/// This is useful when the VirtualDom must be driven from outside a thread and it doesn't make sense to wait for the
|
||||||
/// VirtualDom to be created just to retrieve its channel receiver.
|
/// VirtualDom to be created just to retrieve its channel receiver.
|
||||||
pub fn new_with_props_and_scheduler<P: 'static>(
|
pub fn new_with_props_and_scheduler<P: 'static>(
|
||||||
root: FC<P>,
|
root: Component<P>,
|
||||||
root_props: P,
|
root_props: P,
|
||||||
sender: UnboundedSender<SchedulerMsg>,
|
sender: UnboundedSender<SchedulerMsg>,
|
||||||
receiver: UnboundedReceiver<SchedulerMsg>,
|
receiver: UnboundedReceiver<SchedulerMsg>,
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn test_borrowed_state() {
|
||||||
let _ = VirtualDom::new(Parent);
|
let _ = VirtualDom::new(Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Parent(cx: Context, props: &()) -> Element {
|
fn Parent(cx: Context, _props: &()) -> Element {
|
||||||
let value = cx.use_hook(|_| String::new(), |f| &*f);
|
let value = cx.use_hook(|_| String::new(), |f| &*f);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(unused, non_upper_case_globals)]
|
#![allow(unused, non_upper_case_globals, non_snake_case)]
|
||||||
|
|
||||||
//! Prove that the dom works normally through virtualdom methods.
|
//! Prove that the dom works normally through virtualdom methods.
|
||||||
//!
|
//!
|
||||||
|
@ -13,7 +13,7 @@ use dioxus_html as dioxus_elements;
|
||||||
mod test_logging;
|
mod test_logging;
|
||||||
use DomEdit::*;
|
use DomEdit::*;
|
||||||
|
|
||||||
fn new_dom<P: 'static + Send>(app: FC<P>, props: P) -> VirtualDom {
|
fn new_dom<P: 'static + Send>(app: Component<P>, props: P) -> VirtualDom {
|
||||||
const IS_LOGGING_ENABLED: bool = false;
|
const IS_LOGGING_ENABLED: bool = false;
|
||||||
test_logging::set_up_logging(IS_LOGGING_ENABLED);
|
test_logging::set_up_logging(IS_LOGGING_ENABLED);
|
||||||
VirtualDom::new_with_props(app, props)
|
VirtualDom::new_with_props(app, props)
|
||||||
|
@ -21,7 +21,7 @@ fn new_dom<P: 'static + Send>(app: FC<P>, props: P) -> VirtualDom {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_original_diff() {
|
fn test_original_diff() {
|
||||||
static APP: FC<()> = |cx, props| {
|
static APP: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
div {
|
div {
|
||||||
|
@ -57,7 +57,7 @@ fn test_original_diff() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create() {
|
fn create() {
|
||||||
static APP: FC<()> = |cx, props| {
|
static APP: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
div {
|
div {
|
||||||
|
@ -120,7 +120,7 @@ fn create() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_list() {
|
fn create_list() {
|
||||||
static APP: FC<()> = |cx, props| {
|
static APP: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
{(0..3).map(|f| rsx!{ div {
|
{(0..3).map(|f| rsx!{ div {
|
||||||
"hello"
|
"hello"
|
||||||
|
@ -169,7 +169,7 @@ fn create_list() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_simple() {
|
fn create_simple() {
|
||||||
static APP: FC<()> = |cx, props| {
|
static APP: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {}
|
div {}
|
||||||
div {}
|
div {}
|
||||||
|
@ -207,7 +207,7 @@ fn create_simple() {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn create_components() {
|
fn create_components() {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
Child { "abc1" }
|
Child { "abc1" }
|
||||||
Child { "abc2" }
|
Child { "abc2" }
|
||||||
|
@ -273,7 +273,7 @@ fn create_components() {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn anchors() {
|
fn anchors() {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
{true.then(|| rsx!{ div { "hello" } })}
|
{true.then(|| rsx!{ div { "hello" } })}
|
||||||
{false.then(|| rsx!{ div { "goodbye" } })}
|
{false.then(|| rsx!{ div { "goodbye" } })}
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn manual_diffing() {
|
||||||
value: Shared<&'static str>,
|
value: Shared<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<AppProps> = |cx, props| {
|
static App: Component<AppProps> = |cx, props| {
|
||||||
let val = props.value.lock().unwrap();
|
let val = props.value.lock().unwrap();
|
||||||
cx.render(rsx! { div { "{val}" } })
|
cx.render(rsx! { div { "{val}" } })
|
||||||
};
|
};
|
||||||
|
@ -46,7 +46,7 @@ fn manual_diffing() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn events_generate() {
|
fn events_generate() {
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let mut count = use_state(cx, || 0);
|
let mut count = use_state(cx, || 0);
|
||||||
|
|
||||||
let inner = match *count {
|
let inner = match *count {
|
||||||
|
@ -105,7 +105,7 @@ fn events_generate() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn components_generate() {
|
fn components_generate() {
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let mut render_phase = use_state(cx, || 0);
|
let mut render_phase = use_state(cx, || 0);
|
||||||
render_phase += 1;
|
render_phase += 1;
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ fn components_generate() {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static Child: FC<()> = |cx, _| {
|
static Child: Component<()> = |cx, _| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
h1 {}
|
h1 {}
|
||||||
})
|
})
|
||||||
|
@ -222,7 +222,7 @@ fn components_generate() {
|
||||||
#[test]
|
#[test]
|
||||||
fn component_swap() {
|
fn component_swap() {
|
||||||
// simple_logger::init();
|
// simple_logger::init();
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let mut render_phase = use_state(cx, || 0);
|
let mut render_phase = use_state(cx, || 0);
|
||||||
render_phase += 1;
|
render_phase += 1;
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ fn component_swap() {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static NavBar: FC<()> = |cx, _| {
|
static NavBar: Component<()> = |cx, _| {
|
||||||
println!("running navbar");
|
println!("running navbar");
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -271,7 +271,7 @@ fn component_swap() {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static NavLink: FC<()> = |cx, _| {
|
static NavLink: Component<()> = |cx, _| {
|
||||||
println!("running navlink");
|
println!("running navlink");
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -280,7 +280,7 @@ fn component_swap() {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static Dashboard: FC<()> = |cx, _| {
|
static Dashboard: Component<()> = |cx, _| {
|
||||||
println!("running dashboard");
|
println!("running dashboard");
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
@ -289,7 +289,7 @@ fn component_swap() {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static Results: FC<()> = |cx, _| {
|
static Results: Component<()> = |cx, _| {
|
||||||
println!("running results");
|
println!("running results");
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
|
|
@ -13,12 +13,12 @@ mod test_logging;
|
||||||
fn shared_state_test() {
|
fn shared_state_test() {
|
||||||
struct MySharedState(&'static str);
|
struct MySharedState(&'static str);
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.provide_state(MySharedState("world!"));
|
cx.provide_state(MySharedState("world!"));
|
||||||
cx.render(rsx!(Child {}))
|
cx.render(rsx!(Child {}))
|
||||||
};
|
};
|
||||||
|
|
||||||
static Child: FC<()> = |cx, props| {
|
static Child: Component<()> = |cx, props| {
|
||||||
let shared = cx.consume_state::<MySharedState>()?;
|
let shared = cx.consume_state::<MySharedState>()?;
|
||||||
cx.render(rsx!("Hello, {shared.0}"))
|
cx.render(rsx!("Hello, {shared.0}"))
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@ use DomEdit::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn app_runs() {
|
fn app_runs() {
|
||||||
static App: FC<()> = |cx, props| rsx!(cx, div{"hello"} );
|
static App: Component<()> = |cx, props| rsx!(cx, div{"hello"} );
|
||||||
|
|
||||||
let mut vdom = VirtualDom::new(App);
|
let mut vdom = VirtualDom::new(App);
|
||||||
let edits = vdom.rebuild();
|
let edits = vdom.rebuild();
|
||||||
|
@ -27,7 +27,7 @@ fn app_runs() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fragments_work() {
|
fn fragments_work() {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div{"hello"}
|
div{"hello"}
|
||||||
div{"goodbye"}
|
div{"goodbye"}
|
||||||
|
@ -41,7 +41,7 @@ fn fragments_work() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lists_work() {
|
fn lists_work() {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
h1 {"hello"}
|
h1 {"hello"}
|
||||||
{(0..6).map(|f| rsx!(span{ "{f}" }))}
|
{(0..6).map(|f| rsx!(span{ "{f}" }))}
|
||||||
|
@ -54,7 +54,7 @@ fn lists_work() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn conditional_rendering() {
|
fn conditional_rendering() {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
h1 {"hello"}
|
h1 {"hello"}
|
||||||
{true.then(|| rsx!(span{ "a" }))}
|
{true.then(|| rsx!(span{ "a" }))}
|
||||||
|
@ -87,13 +87,13 @@ fn conditional_rendering() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn child_components() {
|
fn child_components() {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
{true.then(|| rsx!(Child { }))}
|
{true.then(|| rsx!(Child { }))}
|
||||||
{false.then(|| rsx!(Child { }))}
|
{false.then(|| rsx!(Child { }))}
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
static Child: FC<()> = |cx, props| {
|
static Child: Component<()> = |cx, props| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
h1 {"hello"}
|
h1 {"hello"}
|
||||||
h1 {"goodbye"}
|
h1 {"goodbye"}
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn main() {
|
||||||
dioxus_desktop::launch(App, |c| c);
|
dioxus_desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut count = use_state(cx, || 0);
|
let mut count = use_state(cx, || 0);
|
||||||
log::debug!("count is {:?}", count);
|
log::debug!("count is {:?}", count);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ use std::{
|
||||||
sync::atomic::AtomicBool,
|
sync::atomic::AtomicBool,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
use tokio::task::LocalSet;
|
|
||||||
use wry::{
|
use wry::{
|
||||||
application::{
|
application::{
|
||||||
accelerator::{Accelerator, SysMods},
|
accelerator::{Accelerator, SysMods},
|
||||||
|
@ -30,14 +29,14 @@ use wry::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn launch(
|
pub fn launch(
|
||||||
root: FC<()>,
|
root: Component<()>,
|
||||||
config_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>,
|
||||||
) {
|
) {
|
||||||
launch_with_props(root, (), config_builder)
|
launch_with_props(root, (), config_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch_with_props<P: Properties + 'static + Send + Sync>(
|
pub fn launch_with_props<P: Properties + 'static + Send + Sync>(
|
||||||
root: FC<P>,
|
root: Component<P>,
|
||||||
props: P,
|
props: P,
|
||||||
builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
|
builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
|
||||||
) {
|
) {
|
||||||
|
@ -51,7 +50,7 @@ struct Response<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<T: 'static + Send + Sync>(
|
pub fn run<T: 'static + Send + Sync>(
|
||||||
root: FC<T>,
|
root: Component<T>,
|
||||||
props: T,
|
props: T,
|
||||||
user_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
|
user_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
|
||||||
) {
|
) {
|
||||||
|
@ -112,7 +111,7 @@ pub struct DesktopController {
|
||||||
impl DesktopController {
|
impl DesktopController {
|
||||||
// Launch the virtualdom on its own thread managed by tokio
|
// Launch the virtualdom on its own thread managed by tokio
|
||||||
// returns the desktop state
|
// returns the desktop state
|
||||||
pub fn new_on_tokio<P: Send + 'static>(root: FC<P>, props: P) -> Self {
|
pub fn new_on_tokio<P: Send + 'static>(root: Component<P>, props: P) -> Self {
|
||||||
let edit_queue = Arc::new(RwLock::new(VecDeque::new()));
|
let edit_queue = Arc::new(RwLock::new(VecDeque::new()));
|
||||||
let pending_edits = edit_queue.clone();
|
let pending_edits = edit_queue.clone();
|
||||||
|
|
||||||
|
@ -142,7 +141,6 @@ impl DesktopController {
|
||||||
dom.wait_for_work().await;
|
dom.wait_for_work().await;
|
||||||
let mut muts = dom.work_with_deadline(|| false);
|
let mut muts = dom.work_with_deadline(|| false);
|
||||||
while let Some(edit) = muts.pop() {
|
while let Some(edit) = muts.pop() {
|
||||||
log::debug!("found mutations {:?}", muts);
|
|
||||||
edit_queue
|
edit_queue
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -9,3 +9,6 @@ pub use use_shared_state::*;
|
||||||
|
|
||||||
mod usecoroutine;
|
mod usecoroutine;
|
||||||
pub use usecoroutine::*;
|
pub use usecoroutine::*;
|
||||||
|
|
||||||
|
mod usemodel;
|
||||||
|
pub use usemodel::*;
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
type ProvidedState<T> = RefCell<ProvidedStateInner<T>>;
|
type ProvidedState<T> = RefCell<ProvidedStateInner<T>>;
|
||||||
|
|
||||||
// Tracks all the subscribers to a shared State
|
// Tracks all the subscribers to a shared State
|
||||||
pub(crate) struct ProvidedStateInner<T> {
|
pub struct ProvidedStateInner<T> {
|
||||||
value: Rc<RefCell<T>>,
|
value: Rc<RefCell<T>>,
|
||||||
notify_any: Rc<dyn Fn(ScopeId)>,
|
notify_any: Rc<dyn Fn(ScopeId)>,
|
||||||
consumers: HashSet<ScopeId>,
|
consumers: HashSet<ScopeId>,
|
||||||
|
@ -20,6 +20,14 @@ impl<T> ProvidedStateInner<T> {
|
||||||
(self.notify_any)(*consumer);
|
(self.notify_any)(*consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write(&self) -> RefMut<T> {
|
||||||
|
self.value.borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self) -> Ref<T> {
|
||||||
|
self.value.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This hook provides some relatively light ergonomics around shared state.
|
/// This hook provides some relatively light ergonomics around shared state.
|
||||||
|
@ -114,10 +122,10 @@ impl<'a, T: 'static> UseSharedState<'a, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_consumers(self) {
|
pub fn notify_consumers(self) {
|
||||||
// if !self.needs_notification.get() {
|
if !self.needs_notification.get() {
|
||||||
self.root.borrow_mut().notify_consumers();
|
self.root.borrow_mut().notify_consumers();
|
||||||
// self.needs_notification.set(true);
|
self.needs_notification.set(true);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
|
pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
|
||||||
|
@ -138,6 +146,10 @@ impl<'a, T: 'static> UseSharedState<'a, T> {
|
||||||
pub fn write_silent(&self) -> RefMut<'_, T> {
|
pub fn write_silent(&self) -> RefMut<'_, T> {
|
||||||
self.value.borrow_mut()
|
self.value.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inner(&self) -> Rc<RefCell<ProvidedStateInner<T>>> {
|
||||||
|
self.root.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Copy for UseSharedState<'_, T> {}
|
impl<T> Copy for UseSharedState<'_, T> {}
|
||||||
|
|
|
@ -6,9 +6,9 @@ use std::{
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn use_coroutine<'a, F: Future<Output = ()> + 'a>(
|
pub fn use_coroutine<'a, F: Future<Output = ()> + 'static>(
|
||||||
cx: Context<'a>,
|
cx: Context<'a>,
|
||||||
f: impl FnOnce() -> F + 'a,
|
mut f: impl FnMut() -> F + 'a,
|
||||||
) -> CoroutineHandle {
|
) -> CoroutineHandle {
|
||||||
//
|
//
|
||||||
cx.use_hook(
|
cx.use_hook(
|
||||||
|
@ -62,7 +62,7 @@ pub struct CoroutineHandle<'a> {
|
||||||
|
|
||||||
impl<'a> CoroutineHandle<'a> {
|
impl<'a> CoroutineHandle<'a> {
|
||||||
pub fn start(&self) {
|
pub fn start(&self) {
|
||||||
if self.inner.running.get() {
|
if self.is_running() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(submit) = self.inner.submit.borrow_mut().take() {
|
if let Some(submit) = self.inner.submit.borrow_mut().take() {
|
||||||
|
@ -71,5 +71,10 @@ impl<'a> CoroutineHandle<'a> {
|
||||||
self.cx.push_task(|| fut.as_mut().unwrap().as_mut());
|
self.cx.push_task(|| fut.as_mut().unwrap().as_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_running(&self) -> bool {
|
||||||
|
self.inner.running.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resume(&self) {}
|
pub fn resume(&self) {}
|
||||||
}
|
}
|
||||||
|
|
136
packages/hooks/src/usemodel.rs
Normal file
136
packages/hooks/src/usemodel.rs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
//! When building complex components, it's occasionally useful to dip into a pure MVC pattern instead of the
|
||||||
|
//! React hooks pattern. Hooks are useful to abstract over some reusable logic, but many models are not reusable
|
||||||
|
//! in the same way that hooks are.
|
||||||
|
//!
|
||||||
|
//! In these cases, we provide `use_model` - a convenient way of abstracting over some state and async functions.
|
||||||
|
|
||||||
|
use dioxus_core::prelude::Context;
|
||||||
|
use futures::Future;
|
||||||
|
use std::{
|
||||||
|
cell::{Cell, Ref, RefCell, RefMut},
|
||||||
|
marker::PhantomData,
|
||||||
|
pin::Pin,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn use_model<T: 'static>(cx: Context, f: impl FnOnce() -> T) -> UseModel<T> {
|
||||||
|
cx.use_hook(
|
||||||
|
|_| UseModelInner {
|
||||||
|
update_scheduled: Cell::new(false),
|
||||||
|
update_callback: cx.schedule_update(),
|
||||||
|
value: RefCell::new(f()),
|
||||||
|
// tasks: RefCell::new(Vec::new()),
|
||||||
|
},
|
||||||
|
|inner| {
|
||||||
|
inner.update_scheduled.set(false);
|
||||||
|
UseModel { inner }
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UseModel<'a, T> {
|
||||||
|
inner: &'a UseModelInner<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UseModelInner<T> {
|
||||||
|
update_scheduled: Cell<bool>,
|
||||||
|
update_callback: Rc<dyn Fn()>,
|
||||||
|
value: RefCell<T>,
|
||||||
|
// tasks: RefCell<Vec<ModelTask>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModelTask = Pin<Box<dyn Future<Output = ()> + 'static>>;
|
||||||
|
|
||||||
|
impl<'a, T: 'static> UseModel<'a, T> {
|
||||||
|
pub fn read(&self) -> Ref<'_, T> {
|
||||||
|
self.inner.value.borrow()
|
||||||
|
}
|
||||||
|
pub fn write(&self) -> RefMut<'_, T> {
|
||||||
|
self.needs_update();
|
||||||
|
self.inner.value.borrow_mut()
|
||||||
|
}
|
||||||
|
/// Allows the ability to write the value without forcing a re-render
|
||||||
|
pub fn write_silent(&self) -> RefMut<'_, T> {
|
||||||
|
self.inner.value.borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needs_update(&self) {
|
||||||
|
if !self.inner.update_scheduled.get() {
|
||||||
|
self.inner.update_scheduled.set(true);
|
||||||
|
(self.inner.update_callback)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&self, new: T) {
|
||||||
|
*self.inner.value.borrow_mut() = new;
|
||||||
|
self.needs_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
|
||||||
|
(self.read(), self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&self, f: impl FnOnce() -> ModelTask) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep a coroutine going
|
||||||
|
pub fn use_model_coroutine<T, F: Future<Output = ()> + 'static>(
|
||||||
|
cx: Context,
|
||||||
|
model: UseModel<T>,
|
||||||
|
f: impl FnOnce(AppModels) -> F,
|
||||||
|
) -> UseModelCoroutine {
|
||||||
|
cx.use_hook(
|
||||||
|
|_| {
|
||||||
|
//
|
||||||
|
UseModelTaskInner {
|
||||||
|
task: Default::default(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|inner| {
|
||||||
|
if let Some(task) = inner.task.get_mut() {
|
||||||
|
cx.push_task(|| task);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
todo!()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UseModelCoroutine {}
|
||||||
|
|
||||||
|
struct UseModelTaskInner {
|
||||||
|
task: RefCell<Option<ModelTask>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UseModelCoroutine {
|
||||||
|
pub fn start(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ModelAsync<T> {
|
||||||
|
_p: PhantomData<T>,
|
||||||
|
}
|
||||||
|
impl<T> ModelAsync<T> {
|
||||||
|
pub fn write(&self) -> RefMut<'_, T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
pub fn read(&self) -> Ref<'_, T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AppModels {}
|
||||||
|
|
||||||
|
impl AppModels {
|
||||||
|
pub fn get<T: 'static>(&self) -> ModelAsync<T> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Copy for UseModel<'_, T> {}
|
||||||
|
impl<'a, T> Clone for UseModel<'a, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { inner: self.inner }
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,12 +8,12 @@ use dioxus_core::Context;
|
||||||
pub fn use_ref<T: 'static>(cx: Context, f: impl FnOnce() -> T) -> UseRef<T> {
|
pub fn use_ref<T: 'static>(cx: Context, f: impl FnOnce() -> T) -> UseRef<T> {
|
||||||
cx.use_hook(
|
cx.use_hook(
|
||||||
|_| UseRefInner {
|
|_| UseRefInner {
|
||||||
update_scheuled: Cell::new(false),
|
update_scheduled: Cell::new(false),
|
||||||
update_callback: cx.schedule_update(),
|
update_callback: cx.schedule_update(),
|
||||||
value: RefCell::new(f()),
|
value: RefCell::new(f()),
|
||||||
},
|
},
|
||||||
|inner| {
|
|inner| {
|
||||||
inner.update_scheuled.set(false);
|
inner.update_scheduled.set(false);
|
||||||
UseRef { inner }
|
UseRef { inner }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -23,7 +23,7 @@ pub struct UseRef<'a, T> {
|
||||||
inner: &'a UseRefInner<T>,
|
inner: &'a UseRefInner<T>,
|
||||||
}
|
}
|
||||||
struct UseRefInner<T> {
|
struct UseRefInner<T> {
|
||||||
update_scheuled: Cell<bool>,
|
update_scheduled: Cell<bool>,
|
||||||
update_callback: Rc<dyn Fn()>,
|
update_callback: Rc<dyn Fn()>,
|
||||||
value: RefCell<T>,
|
value: RefCell<T>,
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,8 @@ impl<'a, T> UseRef<'a, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn needs_update(&self) {
|
pub fn needs_update(&self) {
|
||||||
if !self.inner.update_scheuled.get() {
|
if !self.inner.update_scheduled.get() {
|
||||||
self.inner.update_scheuled.set(true);
|
self.inner.update_scheduled.set(true);
|
||||||
(self.inner.update_callback)();
|
(self.inner.update_callback)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
|
|
||||||
/// Store state between component renders!
|
/// Store state between component renders!
|
||||||
///
|
///
|
||||||
/// ## The "Pinnacle" of state hooks
|
/// ## Dioxus equivalent of useState, designed for Rust
|
||||||
///
|
///
|
||||||
/// The Dioxus version of `useState` is the "king daddy" of state management. It allows you to ergonomically store and
|
/// The Dioxus version of `useState` is the "king daddy" of state management. It allows you to ergonomically store and
|
||||||
/// modify state between component renders. When the state is updated, the component will re-render.
|
/// modify state between component renders. When the state is updated, the component will re-render.
|
||||||
|
@ -54,17 +54,15 @@ pub fn use_state<'a, T: 'static>(
|
||||||
initial_state_fn: impl FnOnce() -> T,
|
initial_state_fn: impl FnOnce() -> T,
|
||||||
) -> UseState<'a, T> {
|
) -> UseState<'a, T> {
|
||||||
cx.use_hook(
|
cx.use_hook(
|
||||||
move |_| {
|
move |_| UseStateInner {
|
||||||
//
|
current_val: initial_state_fn(),
|
||||||
UseStateInner {
|
update_callback: cx.schedule_update(),
|
||||||
current_val: initial_state_fn(),
|
wip: Rc::new(RefCell::new(None)),
|
||||||
update_callback: cx.schedule_update(),
|
update_scheuled: Cell::new(false),
|
||||||
wip: Rc::new(RefCell::new(None)),
|
|
||||||
update_scheuled: Cell::new(false),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
move |hook| {
|
move |hook| {
|
||||||
hook.update_scheuled.set(false);
|
hook.update_scheuled.set(false);
|
||||||
|
|
||||||
let mut new_val = hook.wip.borrow_mut();
|
let mut new_val = hook.wip.borrow_mut();
|
||||||
if new_val.is_some() {
|
if new_val.is_some() {
|
||||||
hook.current_val = new_val.take().unwrap();
|
hook.current_val = new_val.take().unwrap();
|
||||||
|
@ -134,13 +132,13 @@ impl<'a, T: 'static> UseState<'a, T> {
|
||||||
pub fn setter(&self) -> Rc<dyn Fn(T)> {
|
pub fn setter(&self) -> Rc<dyn Fn(T)> {
|
||||||
let slot = self.inner.wip.clone();
|
let slot = self.inner.wip.clone();
|
||||||
Rc::new(move |new| {
|
Rc::new(move |new| {
|
||||||
//
|
|
||||||
*slot.borrow_mut() = Some(new);
|
*slot.borrow_mut() = Some(new);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_async(&self) -> AsyncUseState<T> {
|
pub fn for_async(&self) -> AsyncUseState<T> {
|
||||||
AsyncUseState {
|
AsyncUseState {
|
||||||
|
re_render: self.inner.update_callback.clone(),
|
||||||
wip: self.inner.wip.clone(),
|
wip: self.inner.wip.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +167,10 @@ impl<'a, T: 'static + ToOwned<Owned = T>> UseState<'a, T> {
|
||||||
slot.as_mut().unwrap()
|
slot.as_mut().unwrap()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inner(self) -> T {
|
||||||
|
self.inner.current_val.to_owned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> std::ops::Deref for UseState<'a, T> {
|
impl<'a, T> std::ops::Deref for UseState<'a, T> {
|
||||||
|
@ -254,6 +256,7 @@ impl<'a, T: 'static + Display> std::fmt::Display for UseState<'a, T> {
|
||||||
|
|
||||||
/// A less ergonmic but still capable form of use_state that's valid for `static lifetime
|
/// A less ergonmic but still capable form of use_state that's valid for `static lifetime
|
||||||
pub struct AsyncUseState<T: 'static> {
|
pub struct AsyncUseState<T: 'static> {
|
||||||
|
re_render: Rc<dyn Fn()>,
|
||||||
wip: Rc<RefCell<Option<T>>>,
|
wip: Rc<RefCell<Option<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +272,10 @@ impl<T: ToOwned> AsyncUseState<T> {
|
||||||
slot.as_mut().unwrap()
|
slot.as_mut().unwrap()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
impl<T> AsyncUseState<T> {
|
||||||
pub fn set(&mut self, val: T) {
|
pub fn set(&mut self, val: T) {
|
||||||
|
(self.re_render)();
|
||||||
*self.wip.borrow_mut() = Some(val);
|
*self.wip.borrow_mut() = Some(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,11 @@ pub mod on {
|
||||||
// ie copy
|
// ie copy
|
||||||
let shortname: &'static str = &event_name[2..];
|
let shortname: &'static str = &event_name[2..];
|
||||||
|
|
||||||
c.listener(shortname, callback)
|
let handler = EventHandler {
|
||||||
|
callback: bump.alloc(std::cell::RefCell::new(Some(callback))),
|
||||||
|
};
|
||||||
|
|
||||||
|
c.listener(shortname, handler)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
)*
|
)*
|
||||||
|
|
19
packages/liveview/Cargo.toml
Normal file
19
packages/liveview/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "dioxus-liveview"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = { version = "0.4.2", optional = true, features = ["ws", "headers"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["axum"]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1.14.0", features = ["full"] }
|
||||||
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
tower-http = { version = "0.2.0", features = ["fs", "trace"] }
|
||||||
|
headers = "0.3"
|
24
packages/liveview/README.md
Normal file
24
packages/liveview/README.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Dioxus LiveView
|
||||||
|
|
||||||
|
Enabling server-rendered and hybrid applications with incredibly low latency (<1ms).
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() -> tide::Result<()> {
|
||||||
|
let liveview_pool = dioxus::liveview::pool::default();
|
||||||
|
let mut app = tide::new();
|
||||||
|
|
||||||
|
// serve the liveview client
|
||||||
|
app.at("/").get(dioxus::liveview::liveview_frontend);
|
||||||
|
|
||||||
|
// and then connect the client to the backend
|
||||||
|
app.at("/app").get(|req| dioxus::liveview::launch(App, Props { req }))
|
||||||
|
|
||||||
|
app.listen("127.0.0.1:8080").await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dioxus LiveView runs your Dioxus apps on the server
|
||||||
|
|
96
packages/liveview/examples/axum.rs
Normal file
96
packages/liveview/examples/axum.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
//! Example websocket server.
|
||||||
|
//!
|
||||||
|
//! Run with
|
||||||
|
//!
|
||||||
|
//! ```not_rust
|
||||||
|
//! cargo run -p example-websockets
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
extract::{
|
||||||
|
ws::{Message, WebSocket, WebSocketUpgrade},
|
||||||
|
TypedHeader,
|
||||||
|
},
|
||||||
|
http::StatusCode,
|
||||||
|
response::IntoResponse,
|
||||||
|
routing::{get, get_service},
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use tower_http::{
|
||||||
|
services::ServeDir,
|
||||||
|
trace::{DefaultMakeSpan, TraceLayer},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
// Set the RUST_LOG, if it hasn't been explicitly defined
|
||||||
|
if std::env::var_os("RUST_LOG").is_none() {
|
||||||
|
std::env::set_var("RUST_LOG", "example_websockets=debug,tower_http=debug")
|
||||||
|
}
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
// build our application with some routes
|
||||||
|
let app = Router::new()
|
||||||
|
.fallback(
|
||||||
|
get_service(
|
||||||
|
ServeDir::new("examples/axum_assets").append_index_html_on_directories(true),
|
||||||
|
)
|
||||||
|
.handle_error(|error: std::io::Error| async move {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("Unhandled internal error: {}", error),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
// routes are matched from bottom to top, so we have to put `nest` at the
|
||||||
|
// top since it matches all routes
|
||||||
|
.route("/ws", get(ws_handler))
|
||||||
|
// logging so we can see whats going on
|
||||||
|
.layer(
|
||||||
|
TraceLayer::new_for_http()
|
||||||
|
.make_span_with(DefaultMakeSpan::default().include_headers(true)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// run it with hyper
|
||||||
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
|
tracing::debug!("listening on {}", addr);
|
||||||
|
axum::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ws_handler(
|
||||||
|
ws: WebSocketUpgrade,
|
||||||
|
user_agent: Option<TypedHeader<headers::UserAgent>>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
if let Some(TypedHeader(user_agent)) = user_agent {
|
||||||
|
println!("`{}` connected", user_agent.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.on_upgrade(handle_socket)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_socket(mut socket: WebSocket) {
|
||||||
|
if let Some(msg) = socket.recv().await {
|
||||||
|
if let Ok(msg) = msg {
|
||||||
|
println!("Client says: {:?}", msg);
|
||||||
|
} else {
|
||||||
|
println!("client disconnected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if socket
|
||||||
|
.send(Message::Text(String::from("Hi!")))
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
println!("client disconnected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
}
|
1
packages/liveview/examples/axum_assets/index.html
Normal file
1
packages/liveview/examples/axum_assets/index.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<script src='script.js'></script>
|
9
packages/liveview/examples/axum_assets/script.js
Normal file
9
packages/liveview/examples/axum_assets/script.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
const socket = new WebSocket('ws://localhost:3000/ws');
|
||||||
|
|
||||||
|
socket.addEventListener('open', function (event) {
|
||||||
|
socket.send('Hello Server!');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener('message', function (event) {
|
||||||
|
console.log('Message from server ', event.data);
|
||||||
|
});
|
0
packages/liveview/src/lib.rs
Normal file
0
packages/liveview/src/lib.rs
Normal file
0
packages/liveview/src/supported/actix_handler.rs
Normal file
0
packages/liveview/src/supported/actix_handler.rs
Normal file
0
packages/liveview/src/supported/axum_handler.rs
Normal file
0
packages/liveview/src/supported/axum_handler.rs
Normal file
0
packages/liveview/src/supported/tide_handler.rs
Normal file
0
packages/liveview/src/supported/tide_handler.rs
Normal file
|
@ -26,11 +26,14 @@ fn init_logging() {
|
||||||
|
|
||||||
static HTML_CONTENT: &'static str = include_str!("../../desktop/src/index.html");
|
static HTML_CONTENT: &'static str = include_str!("../../desktop/src/index.html");
|
||||||
|
|
||||||
pub fn launch(root: FC<()>, builder: fn(WindowBuilder) -> WindowBuilder) -> anyhow::Result<()> {
|
pub fn launch(
|
||||||
|
root: Component<()>,
|
||||||
|
builder: fn(WindowBuilder) -> WindowBuilder,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
launch_with_props(root, (), builder)
|
launch_with_props(root, (), builder)
|
||||||
}
|
}
|
||||||
pub fn launch_with_props<P: 'static + Send>(
|
pub fn launch_with_props<P: 'static + Send>(
|
||||||
root: FC<P>,
|
root: Component<P>,
|
||||||
props: P,
|
props: P,
|
||||||
builder: fn(WindowBuilder) -> WindowBuilder,
|
builder: fn(WindowBuilder) -> WindowBuilder,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
@ -41,7 +44,7 @@ pub fn launch_with_props<P: 'static + Send>(
|
||||||
/// Components used in WebviewRenderer instances can directly use system libraries, access the filesystem, and multithread with ease.
|
/// Components used in WebviewRenderer instances can directly use system libraries, access the filesystem, and multithread with ease.
|
||||||
pub struct WebviewRenderer<T> {
|
pub struct WebviewRenderer<T> {
|
||||||
/// The root component used to render the Webview
|
/// The root component used to render the Webview
|
||||||
root: FC<T>,
|
root: Component<T>,
|
||||||
}
|
}
|
||||||
enum RpcEvent<'a> {
|
enum RpcEvent<'a> {
|
||||||
Initialize {
|
Initialize {
|
||||||
|
@ -52,7 +55,7 @@ enum RpcEvent<'a> {
|
||||||
|
|
||||||
impl<T: 'static + Send> WebviewRenderer<T> {
|
impl<T: 'static + Send> WebviewRenderer<T> {
|
||||||
pub fn run(
|
pub fn run(
|
||||||
root: FC<T>,
|
root: Component<T>,
|
||||||
props: T,
|
props: T,
|
||||||
user_builder: fn(WindowBuilder) -> WindowBuilder,
|
user_builder: fn(WindowBuilder) -> WindowBuilder,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
@ -60,7 +63,7 @@ impl<T: 'static + Send> WebviewRenderer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_with_edits(
|
pub fn run_with_edits(
|
||||||
root: FC<T>,
|
root: Component<T>,
|
||||||
props: T,
|
props: T,
|
||||||
user_builder: fn(WindowBuilder) -> WindowBuilder,
|
user_builder: fn(WindowBuilder) -> WindowBuilder,
|
||||||
redits: Option<Vec<DomEdit<'static>>>,
|
redits: Option<Vec<DomEdit<'static>>>,
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
||||||
dioxus_web::launch(App, |c| c);
|
dioxus_web::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
enum Route {
|
enum Route {
|
||||||
Home,
|
Home,
|
||||||
|
|
|
@ -301,13 +301,13 @@ mod tests {
|
||||||
use dioxus_core_macro::*;
|
use dioxus_core_macro::*;
|
||||||
use dioxus_html as dioxus_elements;
|
use dioxus_html as dioxus_elements;
|
||||||
|
|
||||||
static SIMPLE_APP: FC<()> = |cx, _| {
|
static SIMPLE_APP: Component<()> = |cx, _| {
|
||||||
cx.render(rsx!(div {
|
cx.render(rsx!(div {
|
||||||
"hello world!"
|
"hello world!"
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
static SLIGHTLY_MORE_COMPLEX: FC<()> = |cx, _| {
|
static SLIGHTLY_MORE_COMPLEX: Component<()> = |cx, _| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
title: "About W3Schools"
|
title: "About W3Schools"
|
||||||
|
@ -326,14 +326,14 @@ mod tests {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
static NESTED_APP: FC<()> = |cx, _| {
|
static NESTED_APP: Component<()> = |cx, _| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div {
|
div {
|
||||||
SIMPLE_APP {}
|
SIMPLE_APP {}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
static FRAGMENT_APP: FC<()> = |cx, _| {
|
static FRAGMENT_APP: Component<()> = |cx, _| {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div { "f1" }
|
div { "f1" }
|
||||||
div { "f2" }
|
div { "f2" }
|
||||||
|
@ -389,7 +389,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn styles() {
|
fn styles() {
|
||||||
static STLYE_APP: FC<()> = |cx, _| {
|
static STLYE_APP: Component<()> = |cx, _| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { color: "blue", font_size: "46px" }
|
div { color: "blue", font_size: "46px" }
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
||||||
dioxus_web::launch(App, |c| c);
|
dioxus_web::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let mut count = use_state(cx, || 0);
|
let mut count = use_state(cx, || 0);
|
||||||
|
|
||||||
cx.push_task(|| async move {
|
cx.push_task(|| async move {
|
||||||
|
|
|
@ -107,7 +107,7 @@ impl Label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, _props| {
|
static App: Component<()> = |cx, _props| {
|
||||||
let mut items = use_ref(cx, || vec![]);
|
let mut items = use_ref(cx, || vec![]);
|
||||||
let mut selected = use_state(cx, || None);
|
let mut selected = use_state(cx, || None);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn main() {
|
||||||
dioxus_web::launch(App, |c| c);
|
dioxus_web::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, props| {
|
static App: Component<()> = |cx, props| {
|
||||||
let show = use_state(cx, || true);
|
let show = use_state(cx, || true);
|
||||||
|
|
||||||
let inner = match *show {
|
let inner = match *show {
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
||||||
dioxus_web::launch(App, |c| c);
|
dioxus_web::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx, _| {
|
static App: Component<()> = |cx, _| {
|
||||||
let doggo = cx.suspend(|| async move {
|
let doggo = cx.suspend(|| async move {
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct Doggo {
|
struct Doggo {
|
||||||
|
|
|
@ -60,7 +60,7 @@ use cache::intern_cached_strings;
|
||||||
use dioxus::SchedulerMsg;
|
use dioxus::SchedulerMsg;
|
||||||
use dioxus::VirtualDom;
|
use dioxus::VirtualDom;
|
||||||
pub use dioxus_core as dioxus;
|
pub use dioxus_core as dioxus;
|
||||||
use dioxus_core::prelude::FC;
|
use dioxus_core::prelude::Component;
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
|
@ -89,7 +89,7 @@ mod ric_raf;
|
||||||
/// rsx!(cx, div {"hello world"})
|
/// rsx!(cx, div {"hello world"})
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> WebConfig) {
|
pub fn launch(root_component: Component<()>, configuration: impl FnOnce(WebConfig) -> WebConfig) {
|
||||||
launch_with_props(root_component, (), configuration)
|
launch_with_props(root_component, (), configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +113,11 @@ pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> W
|
||||||
/// rsx!(cx, div {"hello {props.name}"})
|
/// rsx!(cx, div {"hello {props.name}"})
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn launch_with_props<T, F>(root_component: FC<T>, root_properties: T, configuration_builder: F)
|
pub fn launch_with_props<T, F>(
|
||||||
where
|
root_component: Component<T>,
|
||||||
|
root_properties: T,
|
||||||
|
configuration_builder: F,
|
||||||
|
) where
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
F: FnOnce(WebConfig) -> WebConfig,
|
F: FnOnce(WebConfig) -> WebConfig,
|
||||||
{
|
{
|
||||||
|
@ -134,7 +137,7 @@ where
|
||||||
/// wasm_bindgen_futures::spawn_local(app_fut);
|
/// wasm_bindgen_futures::spawn_local(app_fut);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg: WebConfig) {
|
pub async fn run_with_props<T: 'static + Send>(root: Component<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);
|
||||||
|
|
||||||
intern_cached_strings();
|
intern_cached_strings();
|
||||||
|
|
Loading…
Reference in a new issue