mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-26 14:10:20 +00:00
feat: upgrade syntax
This commit is contained in:
parent
574d7fdb9e
commit
fd93ee89c1
64 changed files with 522 additions and 437 deletions
|
@ -5,7 +5,7 @@ fn main() {
|
|||
dom.rebuild();
|
||||
}
|
||||
|
||||
const App: FC<()> = |(cx, props)| {
|
||||
const App: FC<()> = |cx, props| {
|
||||
let id = cx.scope_id();
|
||||
// cx.submit_task(Box::pin(async move { id }));
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ struct SomeContext {
|
|||
}
|
||||
|
||||
#[allow(unused)]
|
||||
static Example: FC<()> = |(cx, props)| {
|
||||
static Example: FC<()> = |cx, props| {
|
||||
todo!()
|
||||
|
||||
// let value = cx.use_context(|c: &SomeContext| c.items.last().unwrap());
|
||||
|
|
|
@ -33,7 +33,7 @@ fn html_usage() {
|
|||
|
||||
static App2: FC<()> = |(cx, _)| cx.render(rsx!("hello world!"));
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let name = cx.use_state(|| 0);
|
||||
|
||||
cx.render(rsx!(div {
|
||||
|
@ -99,7 +99,7 @@ impl<'a> Children<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
static Bapp: FC<()> = |(cx, props)| {
|
||||
static Bapp: FC<()> = |cx, props| {
|
||||
let name = cx.use_state(|| 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
|
@ -114,7 +114,7 @@ static Bapp: FC<()> = |(cx, props)| {
|
|||
))
|
||||
};
|
||||
|
||||
static Match: FC<()> = |(cx, props)| {
|
||||
static Match: FC<()> = |cx, props| {
|
||||
//
|
||||
let b: Box<dyn Fn(NodeFactory) -> VNode> = Box::new(|f| todo!());
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use dioxus_core::{lazynodes::LazyNodes, prelude::*};
|
|||
// #[async_std::main]
|
||||
fn main() {
|
||||
static App: FC<()> =
|
||||
|(cx, props)| cx.render(Some(LazyNodes::new(move |f| f.text(format_args!("hello")))));
|
||||
|cx, props| cx.render(Some(LazyNodes::new(move |f| f.text(format_args!("hello")))));
|
||||
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ use dioxus::prelude::*;
|
|||
struct NoKeysProps {
|
||||
data: std::collections::HashMap<u32, String>,
|
||||
}
|
||||
static AntipatternNoKeys: FC<NoKeysProps> = |(cx, props)| {
|
||||
static AntipatternNoKeys: FC<NoKeysProps> = |cx, props| {
|
||||
// WRONG: Make sure to add keys!
|
||||
rsx!(cx, ul {
|
||||
{props.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
|
||||
|
@ -54,7 +54,7 @@ static AntipatternNoKeys: FC<NoKeysProps> = |(cx, props)| {
|
|||
///
|
||||
/// Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing
|
||||
/// an API for registering shared state without the ContextProvider pattern.
|
||||
static AntipatternNestedFragments: FC<()> = |(cx, props)| {
|
||||
static AntipatternNestedFragments: FC<()> = |cx, props| {
|
||||
// Try to avoid heavily nesting fragments
|
||||
rsx!(cx,
|
||||
Fragment {
|
||||
|
@ -82,7 +82,7 @@ static AntipatternNestedFragments: FC<()> = |(cx, props)| {
|
|||
/// However, calling set_state will *not* update the current version of state in the component. This should be easy to
|
||||
/// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state`
|
||||
/// merely places a new value in the queue and schedules the component for a future update.
|
||||
static AntipatternRelyingOnSetState: FC<()> = |(cx, props)| {
|
||||
static AntipatternRelyingOnSetState: FC<()> = |cx, props| {
|
||||
let (state, set_state) = use_state(cx, || "Hello world").classic();
|
||||
set_state("New state");
|
||||
// This will return false! `state` will *still* be "Hello world"
|
||||
|
@ -99,7 +99,7 @@ static AntipatternRelyingOnSetState: FC<()> = |(cx, props)| {
|
|||
/// - All components must start with an uppercase character
|
||||
///
|
||||
/// i.e.: the following component will be rejected when attempted to be used in the rsx! macro
|
||||
static antipattern_component: FC<()> = |(cx, props)| todo!();
|
||||
static antipattern_component: FC<()> = |cx, props| todo!();
|
||||
|
||||
/// Antipattern: Misusing hooks
|
||||
/// ---------------------------
|
||||
|
@ -120,7 +120,7 @@ static antipattern_component: FC<()> = |(cx, props)| todo!();
|
|||
struct MisuedHooksProps {
|
||||
should_render_state: bool,
|
||||
}
|
||||
static AntipatternMisusedHooks: FC<MisuedHooksProps> = |(cx, props)| {
|
||||
static AntipatternMisusedHooks: FC<MisuedHooksProps> = |cx, props| {
|
||||
if props.should_render_state {
|
||||
// do not place a hook in the conditional!
|
||||
// prefer to move it out of the conditional
|
||||
|
@ -153,7 +153,7 @@ static AntipatternMisusedHooks: FC<MisuedHooksProps> = |(cx, props)| {
|
|||
/// }
|
||||
/// }
|
||||
/// })
|
||||
static _example: FC<()> = |(cx, props)| todo!();
|
||||
static _example: FC<()> = |cx, props| todo!();
|
||||
|
||||
/// Antipattern: publishing components and hooks with all features enabled
|
||||
/// ----------------------------------------------------------------------
|
||||
|
@ -171,9 +171,9 @@ static _example: FC<()> = |(cx, props)| todo!();
|
|||
///
|
||||
/// This will only include the `core` dioxus crate which is relatively slim and fast to compile and avoids target-specific
|
||||
/// libraries.
|
||||
static __example: FC<()> = |(cx, props)| todo!();
|
||||
static __example: FC<()> = |cx, props| todo!();
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
AntipatternNoKeys { data: std::collections::HashMap::new() }
|
||||
AntipatternNestedFragments {}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
Greeting {
|
||||
|
@ -25,7 +25,7 @@ struct GreetingProps {
|
|||
name: &'static str,
|
||||
}
|
||||
|
||||
static Greeting: FC<GreetingProps> = |(cx, props)| {
|
||||
static Greeting: FC<GreetingProps> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "Hello, {props.name}!" }
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
Banner {
|
||||
|
@ -31,7 +31,7 @@ pub static Example: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
pub static Banner: FC<()> = |(cx, props)| {
|
||||
pub static Banner: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "This is a great banner!" }
|
||||
|
|
|
@ -16,7 +16,7 @@ use dioxus::prelude::*;
|
|||
pub struct MyProps {
|
||||
should_show: bool,
|
||||
}
|
||||
pub static Example0: FC<MyProps> = |(cx, props)| {
|
||||
pub static Example0: FC<MyProps> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
{props.should_show.then(|| rsx!{
|
||||
|
@ -39,7 +39,7 @@ pub static Example0: FC<MyProps> = |(cx, props)| {
|
|||
pub struct MyProps1 {
|
||||
should_show: bool,
|
||||
}
|
||||
pub static Example1: FC<MyProps1> = |(cx, props)| {
|
||||
pub static Example1: FC<MyProps1> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
// With matching
|
||||
|
@ -77,7 +77,7 @@ pub enum Color {
|
|||
pub struct MyProps2 {
|
||||
color: Color,
|
||||
}
|
||||
pub static Example2: FC<MyProps2> = |(cx, props)| {
|
||||
pub static Example2: FC<MyProps2> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
{match props.color {
|
||||
|
@ -89,7 +89,7 @@ pub static Example2: FC<MyProps2> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let should_show = use_state(cx, || false);
|
||||
let mut color_index = use_state(cx, || 0);
|
||||
let color = match *color_index % 2 {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus::prelude::*;
|
||||
fn main() {}
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub static Example: FC<()> = |(cx, props)| {
|
|||
};
|
||||
|
||||
// A controlled component:
|
||||
static ControlledSelect: FC<()> = |(cx, props)| {
|
||||
static ControlledSelect: FC<()> = |cx, props| {
|
||||
let value = use_state(cx, || String::from("Grapefruit"));
|
||||
cx.render(rsx! {
|
||||
select { value: "{value}", onchange: move |evt| value.set(evt.value()),
|
||||
|
@ -23,7 +23,7 @@ static ControlledSelect: FC<()> = |(cx, props)| {
|
|||
};
|
||||
|
||||
// TODO - how do uncontrolled things work?
|
||||
static UncontrolledSelect: FC<()> = |(cx, props)| {
|
||||
static UncontrolledSelect: FC<()> = |cx, props| {
|
||||
let value = use_state(cx, || String::new());
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
custom_element {
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| cx.render(rsx! { Fragment {} });
|
||||
pub static Example: FC<()> = |cx, props| cx.render(rsx! { Fragment {} });
|
||||
|
|
|
@ -23,14 +23,14 @@ fn main() {}
|
|||
/// This is one way to go about error handling (just toss things away with unwrap).
|
||||
/// However, if you get it wrong, the whole app will crash.
|
||||
/// This is pretty flimsy.
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let data = get_data().unwrap();
|
||||
cx.render(rsx!( div { "{data}" } ))
|
||||
};
|
||||
|
||||
/// This is a pretty verbose way of error handling
|
||||
/// However, it's still pretty good since we don't panic, just fail to render anything
|
||||
static App1: FC<()> = |(cx, props)| {
|
||||
static App1: FC<()> = |cx, props| {
|
||||
let data = match get_data() {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
|
@ -46,7 +46,7 @@ static App1: FC<()> = |(cx, props)| {
|
|||
/// a user is logged in.
|
||||
///
|
||||
/// Dioxus will throw an error in the console if the None-path is ever taken.
|
||||
static App2: FC<()> = |(cx, props)| {
|
||||
static App2: FC<()> = |cx, props| {
|
||||
let data = get_data()?;
|
||||
cx.render(rsx!( div { "{data}" } ))
|
||||
};
|
||||
|
@ -54,14 +54,14 @@ static App2: FC<()> = |(cx, props)| {
|
|||
/// This is top-tier error handling since it displays a failure state.
|
||||
///
|
||||
/// However, the error is lacking in context.
|
||||
static App3: FC<()> = |(cx, props)| match get_data() {
|
||||
static App3: FC<()> = |cx, props| match get_data() {
|
||||
Some(data) => cx.render(rsx!( div { "{data}" } )),
|
||||
None => cx.render(rsx!( div { "Failed to load data :(" } )),
|
||||
};
|
||||
|
||||
/// For errors that return results, it's possible to short-circuit the match-based error handling with `.ok()` which converts
|
||||
/// a Result<T, V> into an Option<T> and lets you abort rendering by early-returning `None`
|
||||
static App4: FC<()> = |(cx, props)| {
|
||||
static App4: FC<()> = |cx, props| {
|
||||
let data = get_data_err().ok()?;
|
||||
cx.render(rsx!( div { "{data}" } ))
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ static App4: FC<()> = |(cx, props)| {
|
|||
/// This is great error handling since it displays a failure state... with context!
|
||||
///
|
||||
/// Hopefully you'll never need to display a screen like this. It's rather bad taste
|
||||
static App5: FC<()> = |(cx, props)| match get_data_err() {
|
||||
static App5: FC<()> = |cx, props| match get_data_err() {
|
||||
Ok(data) => cx.render(rsx!( div { "{data}" } )),
|
||||
Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
use dioxus::prelude::*;
|
||||
|
||||
// Returning multiple elements with rsx! or html!
|
||||
static App1: FC<()> = |(cx, props)| {
|
||||
static App1: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
h1 { }
|
||||
h2 { }
|
||||
|
@ -20,7 +20,7 @@ static App1: FC<()> = |(cx, props)| {
|
|||
};
|
||||
|
||||
// Using the Fragment component
|
||||
static App2: FC<()> = |(cx, props)| {
|
||||
static App2: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
Fragment {
|
||||
div {}
|
||||
|
@ -31,7 +31,7 @@ static App2: FC<()> = |(cx, props)| {
|
|||
};
|
||||
|
||||
// Using the `fragment` method on the NodeFactory
|
||||
static App3: FC<()> = |(cx, props)| {
|
||||
static App3: FC<()> = |cx, props| {
|
||||
cx.render(LazyNodes::new(move |fac| {
|
||||
fac.fragment_from_iter([
|
||||
fac.text(format_args!("A")),
|
||||
|
@ -42,7 +42,7 @@ static App3: FC<()> = |(cx, props)| {
|
|||
}))
|
||||
};
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
App1 {}
|
||||
App2 {}
|
||||
|
|
|
@ -19,7 +19,7 @@ h1 {color: blue;}
|
|||
p {color: red;}
|
||||
"#;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
head { style { "{STYLE}" } }
|
||||
body {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
head {
|
||||
style: { background_color: "powderblue" }
|
||||
|
@ -29,7 +29,7 @@ pub static Example: FC<()> = |(cx, props)| {
|
|||
// .... technically the rsx! macro is slightly broken at the moment and allows styles not wrapped in style {}
|
||||
// I haven't noticed any name collisions yet, and am tentatively leaving this behavior in..
|
||||
// Don't rely on it.
|
||||
static Example2: FC<()> = |(cx, props)| {
|
||||
static Example2: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div { color: "red"
|
||||
"hello world!"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let example_data = use_state(cx, || 0);
|
||||
|
||||
let v = (0..10).map(|f| {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
ButtonList {}
|
||||
NonUpdatingEvents {}
|
||||
|
@ -16,7 +16,7 @@ pub static Example: FC<()> = |(cx, props)| {
|
|||
};
|
||||
|
||||
/// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name.
|
||||
static ButtonList: FC<()> = |(cx, props)| {
|
||||
static ButtonList: FC<()> = |cx, props| {
|
||||
let name = use_state(cx, || "...?");
|
||||
|
||||
let names = ["jack", "jill", "john", "jane"]
|
||||
|
@ -33,7 +33,7 @@ static ButtonList: FC<()> = |(cx, props)| {
|
|||
|
||||
/// This shows how listeners may be without a visible change in the display.
|
||||
/// Check the console.
|
||||
static NonUpdatingEvents: FC<()> = |(cx, props)| {
|
||||
static NonUpdatingEvents: FC<()> = |cx, props| {
|
||||
rsx!(cx, div {
|
||||
button {
|
||||
onclick: move |_| log::info!("Did not cause any updates!")
|
||||
|
@ -42,7 +42,7 @@ static NonUpdatingEvents: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
static DisablePropagation: FC<()> = |(cx, props)| {
|
||||
static DisablePropagation: FC<()> = |cx, props| {
|
||||
rsx!(cx,
|
||||
div {
|
||||
onclick: move |_| log::info!("event propagated to the div!")
|
||||
|
|
|
@ -21,7 +21,7 @@ use dioxus::prelude::*;
|
|||
|
||||
// By default, components with no props are always memoized.
|
||||
// A props of () is considered empty.
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div { "100% memoized!" }
|
||||
})
|
||||
|
@ -35,7 +35,7 @@ pub struct MyProps1 {
|
|||
name: String,
|
||||
}
|
||||
|
||||
pub static Example1: FC<MyProps1> = |(cx, props)| {
|
||||
pub static Example1: FC<MyProps1> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div { "100% memoized! {props.name}" }
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ pub struct MyProps2 {
|
|||
name: std::rc::Rc<str>,
|
||||
}
|
||||
|
||||
pub static Example2: FC<MyProps2> = |(cx, props)| {
|
||||
pub static Example2: FC<MyProps2> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div { "100% memoized! {props.name}" }
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus::prelude::*;
|
||||
fn main() {}
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let p = 10;
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus::prelude::*;
|
||||
fn main() {}
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let props = MyProps {
|
||||
count: 0,
|
||||
live: true,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus::prelude::*;
|
||||
fn main() {}
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ struct DogApi {
|
|||
}
|
||||
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let doggo = use_suspense(
|
||||
cx,
|
||||
|| surf::get(ENDPOINT).recv_json::<DogApi>(),
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let count = use_state(cx, || 0);
|
||||
let mut direction = use_state(cx, || 1);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus::ssr;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let as_string = use_state(cx, || {
|
||||
// Currently, SSR is only supported for whole VirtualDOMs
|
||||
// This is an easy/low hanging fruit to improve upon
|
||||
|
@ -15,7 +15,7 @@ pub static Example: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
static SomeApp: FC<()> = |(cx, props)| {
|
||||
static SomeApp: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div { style: {background_color: "blue"}
|
||||
h1 {"Some amazing app or component"}
|
||||
|
|
|
@ -27,7 +27,7 @@ fn main() {
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let p1 = use_state(cx, || 0);
|
||||
let p2 = use_state(cx, || 0);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ fn main() {
|
|||
dioxus_desktop::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
"hello world!"
|
||||
|
|
|
@ -18,7 +18,7 @@ fn main() {
|
|||
});
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let file_manager = use_ref(cx, || Files::new());
|
||||
let files = file_manager.read();
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ fn main() {
|
|||
dioxus::desktop::launch(App, |c| c.with_prerendered(content));
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let mut val = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -31,7 +31,7 @@ fn main() {
|
|||
});
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let state = use_ref(cx, || Calculator::new());
|
||||
|
||||
let clear_display = state.read().display_value.eq("0");
|
||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
|||
dioxus::desktop::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -23,7 +23,7 @@ pub enum Route {
|
|||
NotFound,
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let route = use_router(cx, Route::parse)?;
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -49,7 +49,7 @@ const NONE_ELEMENT: Option<()> = None;
|
|||
use baller::Baller;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static Example: FC<()> = |(cx, props)| {
|
||||
pub static Example: FC<()> = |cx, props| {
|
||||
let formatting = "formatting!";
|
||||
let formatting_tuple = ("a", "b");
|
||||
let lazy_fmt = format_args!("lazily formatted text");
|
||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
|||
println!("{}", ssr::render_vdom(&vdom, |c| c));
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
h1 { "Title" }
|
||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
|||
)
|
||||
}
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
pub static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
class: "overflow-hidden"
|
||||
|
|
|
@ -42,7 +42,7 @@ fn main() {}
|
|||
// initial_name: String,
|
||||
// }
|
||||
|
||||
// static Example: FC<ExampleProps> = |(cx, props)| {
|
||||
// static Example: FC<ExampleProps> = |cx, props| {
|
||||
// let dispaly_name = use_state(cx, move || props.initial_name.clone());
|
||||
|
||||
// cx.render(rsx! {
|
||||
|
|
|
@ -24,7 +24,7 @@ fn main() {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
pub static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
div { class: "overflow-hidden"
|
||||
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
|
||||
|
@ -39,7 +39,7 @@ pub static App: FC<()> = |(cx, props)| {
|
|||
))
|
||||
};
|
||||
|
||||
pub static Header: FC<()> = |(cx, props)| {
|
||||
pub static Header: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header { class: "text-gray-400 bg-gray-900 body-font"
|
||||
|
@ -65,7 +65,7 @@ pub static Header: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
pub static Hero: FC<()> = |(cx, props)| {
|
||||
pub static Hero: FC<()> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
|
@ -103,7 +103,7 @@ pub static Hero: FC<()> = |(cx, props)| {
|
|||
}
|
||||
})
|
||||
};
|
||||
pub static Entry: FC<()> = |(cx, props)| {
|
||||
pub static Entry: FC<()> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
|
@ -116,7 +116,7 @@ pub static Entry: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
pub static StacksIcon: FC<()> = |(cx, props)| {
|
||||
pub static StacksIcon: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
xmlns: "http://www.w3.org/2000/svg"
|
||||
|
@ -131,7 +131,7 @@ pub static StacksIcon: FC<()> = |(cx, props)| {
|
|||
}
|
||||
))
|
||||
};
|
||||
pub static RightArrowIcon: FC<()> = |(cx, props)| {
|
||||
pub static RightArrowIcon: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
fill: "none"
|
||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
|||
|
||||
const STYLE: &str = "body {overflow:hidden;}";
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
pub static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
div { class: "overflow-hidden"
|
||||
style { "{STYLE}" }
|
||||
|
@ -30,7 +30,7 @@ pub static App: FC<()> = |(cx, props)| {
|
|||
))
|
||||
};
|
||||
|
||||
pub static Header: FC<()> = |(cx, props)| {
|
||||
pub static Header: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
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: FC<()> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
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: FC<()> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
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: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
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: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
fill: "none"
|
||||
|
|
23
examples/tasks.rs
Normal file
23
examples/tasks.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
//! Example: README.md showcase
|
||||
//!
|
||||
//! The example from the README.md.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
fn main() {
|
||||
dioxus::desktop::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |cx, props| {
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.push_task(async {
|
||||
panic!("polled future");
|
||||
//
|
||||
});
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
}
|
||||
})
|
||||
};
|
|
@ -22,7 +22,7 @@ pub struct TodoItem {
|
|||
}
|
||||
|
||||
const STYLE: &str = include_str!("./assets/todomvc.css");
|
||||
const App: FC<()> = |(cx, props)| {
|
||||
const App: FC<()> = |cx, props| {
|
||||
let mut draft = use_state(cx, || "".to_string());
|
||||
let mut todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
|
||||
let mut filter = use_state(cx, || FilterState::All);
|
||||
|
@ -85,7 +85,7 @@ pub struct TodoEntryProps {
|
|||
todo: Rc<TodoItem>,
|
||||
}
|
||||
|
||||
pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
|
||||
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> Element {
|
||||
let mut is_editing = use_state(cx, || false);
|
||||
let mut contents = use_state(cx, || String::from(""));
|
||||
let todo = &props.todo;
|
||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
|||
|
||||
const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather";
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
//
|
||||
let body = use_suspense(
|
||||
cx,
|
||||
|
@ -40,7 +40,7 @@ static App: FC<()> = |(cx, props)| {
|
|||
#[derive(PartialEq, Props)]
|
||||
struct WeatherProps {}
|
||||
|
||||
static WeatherDisplay: FC<WeatherProps> = |(cx, props)| {
|
||||
static WeatherDisplay: FC<WeatherProps> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx!(
|
||||
div { class: "flex items-center justify-center flex-col"
|
||||
|
|
|
@ -24,7 +24,7 @@ fn main() {
|
|||
dioxus_web::launch(App, |c| c)
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let mut state = use_state(cx, || 0);
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
|
|
@ -23,7 +23,7 @@ fn main() {
|
|||
// dioxus::web::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
dbg!("rednering parent");
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
@ -40,7 +40,7 @@ static App: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
static But: FC<()> = |(cx, props)| {
|
||||
static But: FC<()> = |cx, props| {
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
// let d = Dropper { name: "asd" };
|
||||
|
|
|
@ -24,7 +24,7 @@ fn main() {
|
|||
dioxus_web::launch(App, |c| c)
|
||||
}
|
||||
|
||||
pub static App: FC<()> = |(cx, props)| {
|
||||
pub static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
div { class: "overflow-hidden"
|
||||
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
|
||||
|
@ -39,7 +39,7 @@ pub static App: FC<()> = |(cx, props)| {
|
|||
))
|
||||
};
|
||||
|
||||
pub static Header: FC<()> = |(cx, props)| {
|
||||
pub static Header: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header { class: "text-gray-400 bg-gray-900 body-font"
|
||||
|
@ -65,7 +65,7 @@ pub static Header: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
pub static Hero: FC<()> = |(cx, props)| {
|
||||
pub static Hero: FC<()> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
|
@ -103,7 +103,7 @@ pub static Hero: FC<()> = |(cx, props)| {
|
|||
}
|
||||
})
|
||||
};
|
||||
pub static Entry: FC<()> = |(cx, props)| {
|
||||
pub static Entry: FC<()> = |cx, props| {
|
||||
//
|
||||
cx.render(rsx! {
|
||||
section{ class: "text-gray-400 bg-gray-900 body-font"
|
||||
|
@ -116,7 +116,7 @@ pub static Entry: FC<()> = |(cx, props)| {
|
|||
})
|
||||
};
|
||||
|
||||
pub static StacksIcon: FC<()> = |(cx, props)| {
|
||||
pub static StacksIcon: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
// xmlns: "http://www.w3.org/2000/svg"
|
||||
|
@ -131,7 +131,7 @@ pub static StacksIcon: FC<()> = |(cx, props)| {
|
|||
}
|
||||
))
|
||||
};
|
||||
pub static RightArrowIcon: FC<()> = |(cx, props)| {
|
||||
pub static RightArrowIcon: FC<()> = |cx, props| {
|
||||
cx.render(rsx!(
|
||||
svg {
|
||||
fill: "none"
|
||||
|
|
|
@ -19,7 +19,7 @@ fn main() {
|
|||
dioxus::web::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let rows = (0..1_000).map(|f| {
|
||||
let label = Label::new(&mut rng);
|
||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
|||
dioxus::web::launch(App, |c| c);
|
||||
}
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
|
|
|
@ -173,7 +173,7 @@ impl ToTokens for Component {
|
|||
if !self.children.is_empty() {
|
||||
let childs = &self.children;
|
||||
toks.append_all(quote! {
|
||||
.children(ScopeChildren::new(__cx.fragment_from_iter([ #( #childs ),* ])))
|
||||
.children(__cx.create_children([ #( #childs ),* ]))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -321,14 +321,15 @@ impl<'bump> DiffState<'bump> {
|
|||
}
|
||||
|
||||
MountType::Replace { old } => {
|
||||
// todo: a bug here where we remove a node that is alread being replaced
|
||||
if let Some(old_id) = old.try_mounted_id() {
|
||||
self.mutations.replace_with(old_id, nodes_created as u32);
|
||||
self.remove_nodes(Some(old), true);
|
||||
self.remove_nodes(Some(old), false);
|
||||
} else {
|
||||
if let Some(id) = self.find_first_element_id(old) {
|
||||
self.mutations.replace_with(id, nodes_created as u32);
|
||||
}
|
||||
self.remove_nodes(Some(old), true);
|
||||
self.remove_nodes(Some(old), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,7 +488,11 @@ impl<'bump> DiffState<'bump> {
|
|||
}
|
||||
|
||||
fn create_linked_node(&mut self, link: &'bump NodeLink) {
|
||||
todo!()
|
||||
if let Some(cur_scope) = self.stack.current_scope() {
|
||||
link.scope_id.set(Some(cur_scope));
|
||||
let node: &'bump VNode<'static> = unsafe { &*link.node };
|
||||
self.create_node(unsafe { std::mem::transmute(node) });
|
||||
}
|
||||
}
|
||||
|
||||
// =================================
|
||||
|
@ -532,7 +537,6 @@ impl<'bump> DiffState<'bump> {
|
|||
|
||||
fn diff_element_nodes(
|
||||
&mut self,
|
||||
|
||||
old: &'bump VElement<'bump>,
|
||||
new: &'bump VElement<'bump>,
|
||||
old_node: &'bump VNode<'bump>,
|
||||
|
@ -629,10 +633,8 @@ impl<'bump> DiffState<'bump> {
|
|||
|
||||
fn diff_component_nodes(
|
||||
&mut self,
|
||||
|
||||
old_node: &'bump VNode<'bump>,
|
||||
new_node: &'bump VNode<'bump>,
|
||||
|
||||
old: &'bump VComponent<'bump>,
|
||||
new: &'bump VComponent<'bump>,
|
||||
) {
|
||||
|
@ -648,21 +650,20 @@ impl<'bump> DiffState<'bump> {
|
|||
new.associated_scope.set(Some(scope_addr));
|
||||
|
||||
// make sure the component's caller function is up to date
|
||||
let scope = self.scopes.get_scope(&scope_addr).unwrap();
|
||||
let mut items = scope.items.borrow_mut();
|
||||
let scope = unsafe { self.scopes.get_scope_mut(&scope_addr).unwrap() };
|
||||
scope.caller = unsafe { std::mem::transmute(new.caller) };
|
||||
|
||||
// React doesn't automatically memoize, but we do.
|
||||
let props_are_the_same = todo!("reworking component memoization");
|
||||
// let props_are_the_same = todo!("reworking component memoization");
|
||||
// let props_are_the_same = old.comparator.unwrap();
|
||||
let props_are_the_same = old.comparator.unwrap();
|
||||
|
||||
// if self.cfg.force_diff || !props_are_the_same(new) {
|
||||
// let succeeded = scope.run_scope(self);
|
||||
|
||||
// if succeeded {
|
||||
// self.diff_node(scope.frames.wip_head(), scope.frames.fin_head());
|
||||
// }
|
||||
// }
|
||||
if self.force_diff || !props_are_the_same(new) {
|
||||
if self.scopes.run_scope(&scope_addr) {
|
||||
self.diff_node(
|
||||
self.scopes.wip_head(&scope_addr),
|
||||
self.scopes.fin_head(&scope_addr),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.stack.scope_stack.pop();
|
||||
} else {
|
||||
|
@ -1198,7 +1199,6 @@ impl<'bump> DiffState<'bump> {
|
|||
/// remove can happen whenever
|
||||
fn remove_nodes(
|
||||
&mut self,
|
||||
|
||||
nodes: impl IntoIterator<Item = &'bump VNode<'bump>>,
|
||||
gen_muts: bool,
|
||||
) {
|
||||
|
@ -1244,18 +1244,16 @@ impl<'bump> DiffState<'bump> {
|
|||
}
|
||||
|
||||
VNode::Linked(l) => {
|
||||
todo!()
|
||||
let node = unsafe { std::mem::transmute(&*l.node) };
|
||||
self.remove_nodes(Some(node), gen_muts);
|
||||
}
|
||||
|
||||
VNode::Component(c) => {
|
||||
let scope_id = c.associated_scope.get().unwrap();
|
||||
// let scope = self.scopes.get_scope(&scope_id).unwrap();
|
||||
let root = self.scopes.root_node(&scope_id);
|
||||
self.remove_nodes(Some(root), gen_muts);
|
||||
|
||||
log::debug!("Destroying scope {:?}", scope_id);
|
||||
let mut s = self.scopes.try_remove(&scope_id).unwrap();
|
||||
s.hooks.clear_hooks();
|
||||
self.scopes.try_remove(&scope_id).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ fn it_drops() {
|
|||
|
||||
simple_logger::init().unwrap();
|
||||
|
||||
let factory = NodeFactory { bump: &bump };
|
||||
// let factory = NodeFactory { scope: &bump };
|
||||
|
||||
struct DropInner {
|
||||
id: i32,
|
||||
|
|
|
@ -3,21 +3,32 @@
|
|||
//! This module contains an internal API to generate these instructions.
|
||||
|
||||
use crate::innerlude::*;
|
||||
use std::any::Any;
|
||||
use std::{any::Any, fmt::Debug};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mutations<'a> {
|
||||
pub edits: Vec<DomEdit<'a>>,
|
||||
pub noderefs: Vec<NodeRefMutation<'a>>,
|
||||
pub effects: Vec<&'a dyn FnMut()>,
|
||||
}
|
||||
impl Debug for Mutations<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Mutations")
|
||||
.field("edits", &self.edits)
|
||||
.field("noderefs", &self.noderefs)
|
||||
// .field("effects", &self.effects)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
use DomEdit::*;
|
||||
|
||||
impl<'a> Mutations<'a> {
|
||||
pub(crate) fn new() -> Self {
|
||||
let edits = Vec::new();
|
||||
let noderefs = Vec::new();
|
||||
Self { edits, noderefs }
|
||||
Self {
|
||||
edits: Vec::new(),
|
||||
noderefs: Vec::new(),
|
||||
effects: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
|
|
@ -181,7 +181,7 @@ impl<'src> VNode<'src> {
|
|||
pub(crate) fn children(&self) -> &[VNode<'src>] {
|
||||
match &self {
|
||||
VNode::Fragment(f) => f.children,
|
||||
VNode::Component(c) => todo!("children are not accessible through this"),
|
||||
VNode::Component(_c) => todo!("children are not accessible through this"),
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
@ -199,9 +199,9 @@ impl<'src> VNode<'src> {
|
|||
key: f.key,
|
||||
}),
|
||||
VNode::Linked(c) => VNode::Linked(NodeLink {
|
||||
gen_id: c.gen_id,
|
||||
scope_id: c.scope_id,
|
||||
link_idx: c.link_idx,
|
||||
scope_id: c.scope_id.clone(),
|
||||
link_idx: c.link_idx.clone(),
|
||||
node: c.node.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -224,11 +224,7 @@ impl Debug for VNode<'_> {
|
|||
}
|
||||
VNode::Suspended { .. } => write!(s, "VNode::VSuspended"),
|
||||
VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
|
||||
VNode::Linked(c) => write!(
|
||||
s,
|
||||
"VNode::VCached {{ gen_id: {}, scope_id: {:?} }}",
|
||||
c.gen_id, c.scope_id
|
||||
),
|
||||
VNode::Linked(c) => write!(s, "VNode::VCached {{ scope_id: {:?} }}", c.scope_id.get()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -419,9 +415,25 @@ pub struct VSuspended<'a> {
|
|||
/// an `rsx!` call.
|
||||
#[derive(Debug)]
|
||||
pub struct NodeLink {
|
||||
pub(crate) link_idx: usize,
|
||||
pub(crate) gen_id: u32,
|
||||
pub(crate) scope_id: ScopeId,
|
||||
pub(crate) link_idx: Cell<usize>,
|
||||
pub(crate) scope_id: Cell<Option<ScopeId>>,
|
||||
pub(crate) node: *const VNode<'static>,
|
||||
}
|
||||
|
||||
impl PartialEq for NodeLink {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.node == other.node
|
||||
}
|
||||
}
|
||||
impl NodeLink {
|
||||
// we don't want to let users clone NodeLinks
|
||||
pub(crate) fn clone_inner(&self) -> Self {
|
||||
Self {
|
||||
link_idx: self.link_idx.clone(),
|
||||
scope_id: self.scope_id.clone(),
|
||||
node: self.node.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct provides an ergonomic API to quickly build VNodes.
|
||||
|
@ -440,7 +452,7 @@ impl<'a> NodeFactory<'a> {
|
|||
|
||||
#[inline]
|
||||
pub fn bump(&self) -> &'a bumpalo::Bump {
|
||||
self.bump
|
||||
&self.bump
|
||||
}
|
||||
|
||||
/// Directly pass in text blocks without the need to use the format_args macro.
|
||||
|
@ -460,7 +472,7 @@ impl<'a> NodeFactory<'a> {
|
|||
Some(static_str) => (static_str, true),
|
||||
None => {
|
||||
use bumpalo::core_alloc::fmt::Write;
|
||||
let mut str_buf = bumpalo::collections::String::new_in(self.bump());
|
||||
let mut str_buf = bumpalo::collections::String::new_in(self.bump);
|
||||
str_buf.write_fmt(args).unwrap();
|
||||
(str_buf.into_bump_str(), false)
|
||||
}
|
||||
|
@ -516,18 +528,18 @@ impl<'a> NodeFactory<'a> {
|
|||
A: 'a + AsRef<[Attribute<'a>]>,
|
||||
V: 'a + AsRef<[VNode<'a>]>,
|
||||
{
|
||||
let listeners: &'a L = self.bump().alloc(listeners);
|
||||
let listeners: &'a L = self.bump.alloc(listeners);
|
||||
let listeners = listeners.as_ref();
|
||||
|
||||
let attributes: &'a A = self.bump().alloc(attributes);
|
||||
let attributes: &'a A = self.bump.alloc(attributes);
|
||||
let attributes = attributes.as_ref();
|
||||
|
||||
let children: &'a V = self.bump().alloc(children);
|
||||
let children: &'a V = self.bump.alloc(children);
|
||||
let children = children.as_ref();
|
||||
|
||||
let key = key.map(|f| self.raw_text(f).0);
|
||||
|
||||
VNode::Element(self.bump().alloc(VElement {
|
||||
VNode::Element(self.bump.alloc(VElement {
|
||||
tag_name,
|
||||
key,
|
||||
namespace,
|
||||
|
@ -565,7 +577,7 @@ impl<'a> NodeFactory<'a> {
|
|||
where
|
||||
P: Properties + 'a,
|
||||
{
|
||||
let bump = self.bump();
|
||||
let bump = self.bump;
|
||||
let props = bump.alloc(props);
|
||||
let bump_props = props as *mut P as *mut ();
|
||||
let user_fc = component as *const ();
|
||||
|
@ -598,7 +610,6 @@ impl<'a> NodeFactory<'a> {
|
|||
|
||||
let drop_props: &mut dyn FnMut() = bump.alloc_with(|| {
|
||||
move || unsafe {
|
||||
log::debug!("dropping props!");
|
||||
if !has_dropped {
|
||||
let real_other = bump_props as *mut _ as *mut P;
|
||||
let b = BumpBox::from_raw(real_other);
|
||||
|
@ -620,7 +631,6 @@ impl<'a> NodeFactory<'a> {
|
|||
|
||||
let caller: &'a mut dyn Fn(&'a Scope) -> Element =
|
||||
bump.alloc(move |scope: &Scope| -> Element {
|
||||
log::debug!("calling component renderr {:?}", scope.our_arena_idx);
|
||||
let props: &'_ P = unsafe { &*(bump_props as *const P) };
|
||||
let res = component(scope, props);
|
||||
res
|
||||
|
@ -657,7 +667,7 @@ impl<'a> NodeFactory<'a> {
|
|||
self,
|
||||
node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
|
||||
) -> VNode<'a> {
|
||||
let bump = self.bump();
|
||||
let bump = self.bump;
|
||||
let mut nodes = bumpalo::collections::Vec::new_in(bump);
|
||||
|
||||
for node in node_iter {
|
||||
|
@ -697,6 +707,58 @@ impl<'a> NodeFactory<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
// this isn't quite feasible yet
|
||||
// I think we need some form of interior mutability or state on nodefactory that stores which subtree was created
|
||||
pub fn create_children(
|
||||
self,
|
||||
node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
|
||||
) -> Element {
|
||||
let bump = self.bump;
|
||||
let mut nodes = bumpalo::collections::Vec::new_in(bump);
|
||||
|
||||
for node in node_iter {
|
||||
nodes.push(node.into_vnode(self));
|
||||
}
|
||||
|
||||
if nodes.is_empty() {
|
||||
nodes.push(VNode::Anchor(bump.alloc(VAnchor {
|
||||
dom_id: empty_cell(),
|
||||
})));
|
||||
}
|
||||
|
||||
let children = nodes.into_bump_slice();
|
||||
|
||||
// TODO
|
||||
// We need a dedicated path in the rsx! macro that will trigger the "you need keys" warning
|
||||
//
|
||||
// if cfg!(debug_assertions) {
|
||||
// if children.len() > 1 {
|
||||
// if children.last().unwrap().key().is_none() {
|
||||
// log::error!(
|
||||
// r#"
|
||||
// Warning: Each child in an array or iterator should have a unique "key" prop.
|
||||
// Not providing a key will lead to poor performance with lists.
|
||||
// See docs.rs/dioxus for more information.
|
||||
// ---
|
||||
// To help you identify where this error is coming from, we've generated a backtrace.
|
||||
// "#,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
let frag = VNode::Fragment(VFragment {
|
||||
children,
|
||||
key: None,
|
||||
});
|
||||
let ptr = self.bump.alloc(frag) as *const _;
|
||||
Some(NodeLink {
|
||||
link_idx: Default::default(),
|
||||
scope_id: Default::default(),
|
||||
node: unsafe { std::mem::transmute(ptr) },
|
||||
})
|
||||
}
|
||||
|
||||
pub fn annotate_lazy<'z, 'b>(
|
||||
f: impl FnOnce(NodeFactory<'z>) -> VNode<'z> + 'b,
|
||||
) -> Option<LazyNodes<'z, 'b>> {
|
||||
|
@ -796,28 +858,48 @@ impl IntoVNode<'_> for Arguments<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// called cx.render from a helper function
|
||||
impl IntoVNode<'_> for Option<NodeLink> {
|
||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||
fn into_vnode(self, _cx: NodeFactory) -> VNode {
|
||||
match self {
|
||||
Some(node) => VNode::Linked(node),
|
||||
None => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// essentially passing elements through props
|
||||
// just build a new element in place
|
||||
impl IntoVNode<'_> for &Option<NodeLink> {
|
||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||
fn into_vnode(self, _cx: NodeFactory) -> VNode {
|
||||
match self {
|
||||
Some(node) => VNode::Linked(NodeLink {
|
||||
link_idx: node.link_idx.clone(),
|
||||
scope_id: node.scope_id.clone(),
|
||||
node: node.node,
|
||||
}),
|
||||
None => {
|
||||
//
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Conveniently, we also support "None"
|
||||
impl IntoVNode<'_> for NodeLink {
|
||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||
todo!()
|
||||
fn into_vnode(self, _cx: NodeFactory) -> VNode {
|
||||
VNode::Linked(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Conveniently, we also support "None"
|
||||
impl IntoVNode<'_> for &NodeLink {
|
||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||
todo!()
|
||||
fn into_vnode(self, _cx: NodeFactory) -> VNode {
|
||||
VNode::Linked(NodeLink {
|
||||
link_idx: self.link_idx.clone(),
|
||||
scope_id: self.scope_id.clone(),
|
||||
node: self.node,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::innerlude::*;
|
|||
|
||||
use futures_channel::mpsc::UnboundedSender;
|
||||
use fxhash::FxHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::{Cell, RefCell},
|
||||
|
@ -62,9 +63,6 @@ pub struct Scope {
|
|||
// The double-buffering situation that we will use
|
||||
pub(crate) frames: [BumpFrame; 2],
|
||||
|
||||
pub(crate) old_root: RefCell<Option<NodeLink>>,
|
||||
pub(crate) new_root: RefCell<Option<NodeLink>>,
|
||||
|
||||
pub(crate) caller: *const dyn Fn(&Scope) -> Element,
|
||||
|
||||
/*
|
||||
|
@ -241,19 +239,22 @@ impl Scope {
|
|||
/// }
|
||||
///```
|
||||
pub fn render<'src>(&'src self, lazy_nodes: Option<LazyNodes<'src, '_>>) -> Option<NodeLink> {
|
||||
let bump = &self.wip_frame().bump;
|
||||
let frame = self.wip_frame();
|
||||
let bump = &frame.bump;
|
||||
let factory = NodeFactory { bump };
|
||||
let node = lazy_nodes.map(|f| f.call(factory))?;
|
||||
let node = bump.alloc(node);
|
||||
|
||||
let idx = self
|
||||
.wip_frame()
|
||||
.add_node(unsafe { std::mem::transmute(node) });
|
||||
let node_ptr = node as *mut _;
|
||||
let node_ptr = unsafe { std::mem::transmute(node_ptr) };
|
||||
|
||||
Some(NodeLink {
|
||||
gen_id: self.generation.get(),
|
||||
scope_id: self.our_arena_idx,
|
||||
link_idx: idx,
|
||||
})
|
||||
let link = NodeLink {
|
||||
scope_id: Cell::new(Some(self.our_arena_idx)),
|
||||
link_idx: Cell::new(0),
|
||||
node: node_ptr,
|
||||
};
|
||||
|
||||
Some(link)
|
||||
}
|
||||
|
||||
/// Push an effect to be ran after the component has been successfully mounted to the dom
|
||||
|
@ -435,6 +436,7 @@ impl Scope {
|
|||
false => &self.frames[1],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fin_frame(&self) -> &BumpFrame {
|
||||
match self.generation.get() & 1 == 1 {
|
||||
true => &self.frames[0],
|
||||
|
@ -496,28 +498,42 @@ impl Scope {
|
|||
effect();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_node(&self) -> &VNode {
|
||||
let node = *self.wip_frame().nodes.borrow().get(0).unwrap();
|
||||
unsafe { std::mem::transmute(&*node) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BumpFrame {
|
||||
pub(crate) struct BumpFrame {
|
||||
pub bump: Bump,
|
||||
pub nodes: RefCell<Vec<VNode<'static>>>,
|
||||
pub nodes: RefCell<Vec<*const VNode<'static>>>,
|
||||
}
|
||||
impl BumpFrame {
|
||||
pub fn new() -> Self {
|
||||
let bump = Bump::new();
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
let bump = Bump::with_capacity(capacity);
|
||||
|
||||
let node = &*bump.alloc(VText {
|
||||
text: "asd",
|
||||
dom_id: Default::default(),
|
||||
is_static: false,
|
||||
});
|
||||
let nodes = RefCell::new(vec![VNode::Text(unsafe { std::mem::transmute(node) })]);
|
||||
let node = bump.alloc(VNode::Text(unsafe { std::mem::transmute(node) }));
|
||||
let nodes = RefCell::new(vec![node as *const _]);
|
||||
Self { bump, nodes }
|
||||
}
|
||||
fn add_node(&self, node: VNode<'static>) -> usize {
|
||||
|
||||
pub fn allocated_bytes(&self) -> usize {
|
||||
self.bump.allocated_bytes()
|
||||
}
|
||||
|
||||
pub fn assign_nodelink(&self, node: &NodeLink) {
|
||||
let mut nodes = self.nodes.borrow_mut();
|
||||
nodes.push(node);
|
||||
nodes.len() - 1
|
||||
|
||||
let len = nodes.len();
|
||||
nodes.push(node.node);
|
||||
|
||||
node.link_idx.set(len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,11 +547,18 @@ impl BumpFrame {
|
|||
#[derive(Default)]
|
||||
pub(crate) struct HookList {
|
||||
arena: Bump,
|
||||
vals: RefCell<Vec<*mut dyn Any>>,
|
||||
vals: RefCell<SmallVec<[*mut dyn Any; 5]>>,
|
||||
idx: Cell<usize>,
|
||||
}
|
||||
|
||||
impl HookList {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
arena: Bump::with_capacity(capacity),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> {
|
||||
self.vals.borrow().get(self.idx.get()).and_then(|inn| {
|
||||
self.idx.set(self.idx.get() + 1);
|
||||
|
@ -571,7 +594,7 @@ impl HookList {
|
|||
self.cur_idx() >= self.len()
|
||||
}
|
||||
|
||||
pub fn clear_hooks(&mut self) {
|
||||
pub fn clear(&mut self) {
|
||||
self.vals.borrow_mut().drain(..).for_each(|state| {
|
||||
let as_mut = unsafe { &mut *state };
|
||||
let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use fxhash::FxHashMap;
|
||||
use slab::Slab;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
|
@ -7,7 +8,6 @@ use futures_channel::mpsc::UnboundedSender;
|
|||
use crate::innerlude::*;
|
||||
|
||||
pub type FcSlot = *const ();
|
||||
// pub heuristics: FxHashMap<FcSlot, Heuristic>,
|
||||
|
||||
pub struct Heuristic {
|
||||
hook_arena_size: usize,
|
||||
|
@ -21,6 +21,7 @@ pub struct Heuristic {
|
|||
pub(crate) struct ScopeArena {
|
||||
bump: Bump,
|
||||
scopes: RefCell<Vec<*mut Scope>>,
|
||||
pub heuristics: RefCell<FxHashMap<FcSlot, Heuristic>>,
|
||||
free_scopes: RefCell<Vec<ScopeId>>,
|
||||
nodes: RefCell<Slab<*const VNode<'static>>>,
|
||||
pub(crate) sender: UnboundedSender<SchedulerMsg>,
|
||||
|
@ -31,6 +32,7 @@ impl ScopeArena {
|
|||
Self {
|
||||
bump: Bump::new(),
|
||||
scopes: RefCell::new(Vec::new()),
|
||||
heuristics: RefCell::new(FxHashMap::default()),
|
||||
free_scopes: RefCell::new(Vec::new()),
|
||||
nodes: RefCell::new(Slab::new()),
|
||||
sender,
|
||||
|
@ -68,33 +70,53 @@ impl ScopeArena {
|
|||
} else {
|
||||
let scope_id = ScopeId(self.scopes.borrow().len());
|
||||
|
||||
let old_root = NodeLink {
|
||||
link_idx: 0,
|
||||
gen_id: 0,
|
||||
scope_id,
|
||||
};
|
||||
let new_root = NodeLink {
|
||||
link_idx: 0,
|
||||
gen_id: 0,
|
||||
scope_id,
|
||||
let (node_capacity, hook_capacity) = {
|
||||
let heuristics = self.heuristics.borrow();
|
||||
if let Some(heuristic) = heuristics.get(&fc_ptr) {
|
||||
(heuristic.node_arena_size, heuristic.hook_arena_size)
|
||||
} else {
|
||||
(0, 0)
|
||||
}
|
||||
};
|
||||
|
||||
let new_scope = Scope {
|
||||
let mut frames = [BumpFrame::new(node_capacity), BumpFrame::new(node_capacity)];
|
||||
|
||||
frames[0].nodes.get_mut().push({
|
||||
let vnode = frames[0]
|
||||
.bump
|
||||
.alloc(VNode::Text(frames[0].bump.alloc(VText {
|
||||
dom_id: Default::default(),
|
||||
is_static: false,
|
||||
text: "",
|
||||
})));
|
||||
unsafe { std::mem::transmute(vnode as *mut VNode) }
|
||||
});
|
||||
|
||||
frames[1].nodes.get_mut().push({
|
||||
let vnode = frames[1]
|
||||
.bump
|
||||
.alloc(VNode::Text(frames[1].bump.alloc(VText {
|
||||
dom_id: Default::default(),
|
||||
is_static: false,
|
||||
text: "",
|
||||
})));
|
||||
unsafe { std::mem::transmute(vnode as *mut VNode) }
|
||||
});
|
||||
|
||||
let scope = self.bump.alloc(Scope {
|
||||
sender: self.sender.clone(),
|
||||
parent_scope,
|
||||
our_arena_idx: scope_id,
|
||||
height,
|
||||
subtree: Cell::new(subtree),
|
||||
is_subtree_root: Cell::new(false),
|
||||
frames: [BumpFrame::new(), BumpFrame::new()],
|
||||
frames,
|
||||
|
||||
hooks: Default::default(),
|
||||
hooks: HookList::new(hook_capacity),
|
||||
shared_contexts: Default::default(),
|
||||
caller,
|
||||
generation: 0.into(),
|
||||
|
||||
old_root: RefCell::new(Some(old_root)),
|
||||
new_root: RefCell::new(Some(new_root)),
|
||||
items: RefCell::new(SelfReferentialItems {
|
||||
listeners: Default::default(),
|
||||
borrowed_props: Default::default(),
|
||||
|
@ -102,16 +124,42 @@ impl ScopeArena {
|
|||
tasks: Default::default(),
|
||||
pending_effects: Default::default(),
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
let stable = self.bump.alloc(new_scope);
|
||||
self.scopes.borrow_mut().push(stable);
|
||||
self.scopes.borrow_mut().push(scope);
|
||||
scope_id
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_remove(&self, id: &ScopeId) -> Option<Scope> {
|
||||
todo!()
|
||||
pub fn try_remove(&self, id: &ScopeId) -> Option<()> {
|
||||
self.ensure_drop_safety(id);
|
||||
|
||||
let mut scope = unsafe { &mut *self.get_scope_raw(id)? };
|
||||
|
||||
// we're just reusing scopes so we need to clear it out
|
||||
scope.hooks.clear();
|
||||
scope.shared_contexts.get_mut().clear();
|
||||
scope.parent_scope = None;
|
||||
scope.generation.set(0);
|
||||
scope.is_subtree_root.set(false);
|
||||
scope.subtree.set(0);
|
||||
|
||||
let SelfReferentialItems {
|
||||
borrowed_props,
|
||||
listeners,
|
||||
pending_effects,
|
||||
suspended_nodes,
|
||||
tasks,
|
||||
} = scope.items.get_mut();
|
||||
|
||||
borrowed_props.clear();
|
||||
listeners.clear();
|
||||
pending_effects.clear();
|
||||
suspended_nodes.clear();
|
||||
tasks.clear();
|
||||
|
||||
self.free_scopes.borrow_mut().push(*id);
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn reserve_node(&self, node: &VNode) -> ElementId {
|
||||
|
@ -123,16 +171,10 @@ impl ScopeArena {
|
|||
let node = unsafe { std::mem::transmute::<*const VNode, *const VNode>(node) };
|
||||
entry.insert(node);
|
||||
id
|
||||
|
||||
// let nodes = self.nodes.borrow_mut();
|
||||
// let id = nodes.insert(());
|
||||
// let node_id = ElementId(id);
|
||||
// node = Some(node_id);
|
||||
// node_id
|
||||
}
|
||||
|
||||
pub fn collect_garbage(&self, id: ElementId) {
|
||||
todo!()
|
||||
self.nodes.borrow_mut().remove(id.0);
|
||||
}
|
||||
|
||||
// These methods would normally exist on `scope` but they need access to *all* of the scopes
|
||||
|
@ -152,35 +194,25 @@ impl ScopeArena {
|
|||
pub(crate) fn ensure_drop_safety(&self, scope_id: &ScopeId) {
|
||||
let scope = self.get_scope(scope_id).unwrap();
|
||||
|
||||
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)
|
||||
// right now, we don't drop
|
||||
scope
|
||||
.items
|
||||
.borrow_mut()
|
||||
.borrowed_props
|
||||
.drain(..)
|
||||
.for_each(|comp| {
|
||||
// First drop the component's undropped references
|
||||
// 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");
|
||||
|
||||
todo!("move this onto virtualdom");
|
||||
// let scope = unsafe { &mut *scope_id };
|
||||
self.ensure_drop_safety(&scope_id);
|
||||
|
||||
// scope.ensure_drop_safety();
|
||||
|
||||
todo!("drop the component's props");
|
||||
// let mut drop_props = comp.drop_props.borrow_mut().take().unwrap();
|
||||
// drop_props();
|
||||
let mut drop_props = comp.drop_props.borrow_mut().take().unwrap();
|
||||
drop_props();
|
||||
});
|
||||
|
||||
// Now that all the references are gone, we can safely drop our own references in our listeners.
|
||||
scope
|
||||
.items
|
||||
.borrow_mut()
|
||||
items
|
||||
.listeners
|
||||
.drain(..)
|
||||
.for_each(|listener| drop(listener.callback.borrow_mut().take()));
|
||||
|
@ -212,59 +244,58 @@ impl ScopeArena {
|
|||
|
||||
// just forget about our suspended nodes while we're at it
|
||||
items.suspended_nodes.clear();
|
||||
items.tasks.clear();
|
||||
items.pending_effects.clear();
|
||||
|
||||
// guarantee that we haven't screwed up - there should be no latent references anywhere
|
||||
debug_assert!(items.listeners.is_empty());
|
||||
debug_assert!(items.suspended_nodes.is_empty());
|
||||
debug_assert!(items.borrowed_props.is_empty());
|
||||
debug_assert!(items.suspended_nodes.is_empty());
|
||||
debug_assert!(items.tasks.is_empty());
|
||||
debug_assert!(items.pending_effects.is_empty());
|
||||
|
||||
log::debug!("Borrowed stuff is successfully cleared");
|
||||
|
||||
// temporarily cast the vcomponent to the right lifetime
|
||||
// let vcomp = scope.load_vcomp();
|
||||
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
|
||||
scope.wip_frame().nodes.borrow_mut().clear();
|
||||
}
|
||||
|
||||
let render: &dyn Fn(&Scope) -> Element = unsafe { &*scope.caller };
|
||||
|
||||
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
|
||||
scope.wip_frame().nodes.borrow_mut().clear();
|
||||
if let Some(key) = render(scope) {
|
||||
dbg!(key);
|
||||
if let Some(link) = render(scope) {
|
||||
// right now, it's a panic to render a nodelink from another scope
|
||||
// todo: enable this. it should (reasonably) work even if it doesnt make much sense
|
||||
assert_eq!(link.scope_id.get(), Some(*id));
|
||||
|
||||
dbg!(&scope.wip_frame().nodes.borrow_mut());
|
||||
// let mut old = scope.old_root.borrow_mut();
|
||||
// let mut new = scope.new_root.borrow_mut();
|
||||
// nodelinks are not assigned when called and must be done so through the create/diff phase
|
||||
// however, we need to link this one up since it will never be used in diffing
|
||||
scope.wip_frame().assign_nodelink(&link);
|
||||
debug_assert_eq!(scope.wip_frame().nodes.borrow().len(), 1);
|
||||
|
||||
// let new_old = new.clone();
|
||||
// *old = new_old;
|
||||
// *new = Some(key);
|
||||
if !scope.items.borrow().tasks.is_empty() {
|
||||
// self.
|
||||
}
|
||||
|
||||
// dbg!(&old);
|
||||
// dbg!(&new);
|
||||
|
||||
// the user's component succeeded. We can safely cycle to the next frame
|
||||
// scope.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) };
|
||||
scope.cycle_frame();
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// The head of the bumpframe is the first linked NodeLink
|
||||
pub fn wip_head(&self, id: &ScopeId) -> &VNode {
|
||||
let scope = self.get_scope(id).unwrap();
|
||||
let wip_frame = scope.wip_frame();
|
||||
let nodes = wip_frame.nodes.borrow();
|
||||
let node = nodes.get(0).unwrap();
|
||||
let node: &VNode = unsafe { &**nodes.get(0).unwrap() };
|
||||
unsafe { std::mem::transmute::<&VNode, &VNode>(node) }
|
||||
}
|
||||
|
||||
// The head of the bumpframe is the first linked NodeLink
|
||||
pub fn fin_head(&self, id: &ScopeId) -> &VNode {
|
||||
let scope = self.get_scope(id).unwrap();
|
||||
let wip_frame = scope.fin_frame();
|
||||
let nodes = wip_frame.nodes.borrow();
|
||||
let node: &VNode = nodes.get(0).unwrap();
|
||||
let node: &VNode = unsafe { &**nodes.get(0).unwrap() };
|
||||
unsafe { std::mem::transmute::<&VNode, &VNode>(node) }
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ use std::{any::Any, collections::VecDeque};
|
|||
|
||||
/// A virtual node system that progresses user events and diffs UI trees.
|
||||
///
|
||||
///
|
||||
/// ## Guide
|
||||
///
|
||||
/// Components are defined as simple functions that take [`Context`] and a [`Properties`] type and return an [`Element`].
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -105,14 +108,16 @@ pub struct VirtualDom {
|
|||
|
||||
_root_caller: *mut dyn Fn(&Scope) -> Element,
|
||||
|
||||
pub(crate) scopes: Box<ScopeArena>,
|
||||
scopes: Box<ScopeArena>,
|
||||
|
||||
receiver: UnboundedReceiver<SchedulerMsg>,
|
||||
pub(crate) sender: UnboundedSender<SchedulerMsg>,
|
||||
|
||||
// Every component that has futures that need to be polled
|
||||
sender: UnboundedSender<SchedulerMsg>,
|
||||
|
||||
pending_futures: FxHashSet<ScopeId>,
|
||||
|
||||
pending_messages: VecDeque<SchedulerMsg>,
|
||||
|
||||
dirty_scopes: IndexSet<ScopeId>,
|
||||
}
|
||||
|
||||
|
@ -130,7 +135,7 @@ impl VirtualDom {
|
|||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// fn Example(cx: Context<()>) -> DomTree {
|
||||
/// fn Example(cx: Context, props: &()) -> Element {
|
||||
/// cx.render(rsx!( div { "hello world" } ))
|
||||
/// }
|
||||
///
|
||||
|
@ -159,7 +164,7 @@ impl VirtualDom {
|
|||
/// name: &'static str
|
||||
/// }
|
||||
///
|
||||
/// fn Example(cx: Context<SomeProps>) -> DomTree {
|
||||
/// fn Example(cx: Context, props: &SomeProps) -> Element {
|
||||
/// cx.render(rsx!{ div{ "hello {cx.name}" } })
|
||||
/// }
|
||||
///
|
||||
|
@ -172,7 +177,7 @@ impl VirtualDom {
|
|||
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
|
||||
/// let mutations = dom.rebuild();
|
||||
/// ```
|
||||
pub fn new_with_props<P: 'static + Send>(root: FC<P>, root_props: P) -> Self {
|
||||
pub fn new_with_props<P: 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
|
||||
Self::new_with_props_and_scheduler(root, root_props, sender, receiver)
|
||||
}
|
||||
|
@ -230,8 +235,10 @@ impl VirtualDom {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
pub fn get_scheduler_channel(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
|
||||
self.sender.clone()
|
||||
}
|
||||
|
@ -240,8 +247,10 @@ impl VirtualDom {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
pub fn has_any_work(&self) -> bool {
|
||||
!(self.dirty_scopes.is_empty() && self.pending_messages.is_empty())
|
||||
}
|
||||
|
@ -347,7 +356,9 @@ impl VirtualDom {
|
|||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// static App: FC<()> = |cx, props|rsx!(cx, div {"hello"} );
|
||||
/// fn App(cx: Context, props: &()) -> Element {
|
||||
/// cx.render(rsx!( div {"hello"} ))
|
||||
/// }
|
||||
///
|
||||
/// let mut dom = VirtualDom::new(App);
|
||||
///
|
||||
|
@ -368,6 +379,7 @@ impl VirtualDom {
|
|||
/// applied the edits.
|
||||
///
|
||||
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
||||
///
|
||||
pub fn work_with_deadline(&mut self, mut deadline: impl FnMut() -> bool) -> Vec<Mutations> {
|
||||
let mut committed_mutations = vec![];
|
||||
|
||||
|
@ -436,10 +448,7 @@ impl VirtualDom {
|
|||
}
|
||||
}
|
||||
|
||||
// let scopes = &mut self.scopes;
|
||||
let work_completed = diff_state.work(&mut deadline);
|
||||
// let work_completed = crate::diff::work(&mut diff_state, &mut deadline);
|
||||
// let work_completed = crate::diff::work(&mut diff_state, &mut deadline);
|
||||
|
||||
if work_completed {
|
||||
let DiffState {
|
||||
|
@ -454,7 +463,7 @@ impl VirtualDom {
|
|||
}
|
||||
|
||||
// I think the stack should be empty at the end of diffing?
|
||||
debug_assert_eq!(stack.scope_stack.len(), 0);
|
||||
debug_assert_eq!(stack.scope_stack.len(), 1);
|
||||
|
||||
committed_mutations.push(mutations);
|
||||
} else {
|
||||
|
@ -536,74 +545,45 @@ impl VirtualDom {
|
|||
/// let edits = dom.diff();
|
||||
/// ```
|
||||
pub fn hard_diff<'a>(&'a mut self, scope_id: &ScopeId) -> Option<Mutations<'a>> {
|
||||
log::debug!("hard diff {:?}", scope_id);
|
||||
|
||||
if self.scopes.run_scope(scope_id) {
|
||||
let mut diff_machine = DiffState::new(&self.scopes);
|
||||
|
||||
if self.scopes.run_scope(scope_id) {
|
||||
diff_machine.force_diff = true;
|
||||
|
||||
diff_machine.work(|| false);
|
||||
// let scopes = &mut self.scopes;
|
||||
// crate::diff::diff_scope(&mut diff_machine, scope_id);
|
||||
// self.scopes.diff_scope(&mut diff_machine, scope_id);
|
||||
|
||||
// dbg!(&diff_machine.mutations);
|
||||
// let DiffState {
|
||||
// mutations,
|
||||
// stack,
|
||||
// seen_scopes,
|
||||
// force_diff,
|
||||
// ..
|
||||
// } = mutations;
|
||||
|
||||
// let mutations = diff_machine.mutations;
|
||||
|
||||
// Some(unsafe { std::mem::transmute(mutations) })
|
||||
todo!()
|
||||
} else {
|
||||
None
|
||||
diff_machine.diff_scope(scope_id);
|
||||
}
|
||||
Some(diff_machine.mutations)
|
||||
}
|
||||
|
||||
/// Renders an `rsx` call into the Base Scope's allocator.
|
||||
///
|
||||
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
|
||||
pub fn render_vnodes<'a>(&'a self, lazy_nodes: Option<LazyNodes<'a, '_>>) -> &'a VNode<'a> {
|
||||
todo!()
|
||||
let scope = self.scopes.get_scope(&self.base_scope).unwrap();
|
||||
let frame = scope.wip_frame();
|
||||
let factory = NodeFactory { bump: &frame.bump };
|
||||
let node = lazy_nodes.unwrap().call(factory);
|
||||
frame.bump.alloc(node)
|
||||
}
|
||||
|
||||
/// Renders an `rsx` call into the Base Scope's allocator.
|
||||
///
|
||||
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
|
||||
pub fn diff_vnodes<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> {
|
||||
todo!()
|
||||
// let mutations = Mutations::new();
|
||||
// let mut machine: DiffState = todo!();
|
||||
// // let mut machine = DiffState::new(mutations);
|
||||
// // let mut machine = DiffState::new(mutations);
|
||||
// machine.stack.push(DiffInstruction::Diff { new, old });
|
||||
// machine.mutations
|
||||
let mut machine = DiffState::new(&self.scopes);
|
||||
machine.stack.push(DiffInstruction::Diff { new, old });
|
||||
machine.stack.scope_stack.push(self.base_scope);
|
||||
machine.work(|| false);
|
||||
machine.mutations
|
||||
}
|
||||
|
||||
/// Renders an `rsx` call into the Base Scope's allocator.
|
||||
///
|
||||
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
|
||||
pub fn create_vnodes<'a>(&'a self, left: Option<LazyNodes<'a, '_>>) -> Mutations<'a> {
|
||||
todo!()
|
||||
// let old = self.bump.alloc(self.render_direct(left));
|
||||
|
||||
// let mut machine: DiffState = todo!();
|
||||
// // let mut machine = DiffState::new(Mutations::new());
|
||||
// // let mut machine = DiffState::new(Mutations::new());
|
||||
|
||||
// machine.stack.create_node(old, MountType::Append);
|
||||
|
||||
// todo!()
|
||||
|
||||
// // machine.work(&mut || false);
|
||||
|
||||
// // machine.mutations
|
||||
let nodes = self.render_vnodes(left);
|
||||
let mut machine = DiffState::new(&self.scopes);
|
||||
machine.stack.create_node(nodes, MountType::Append);
|
||||
machine.work(|| false);
|
||||
machine.mutations
|
||||
}
|
||||
|
||||
/// Renders an `rsx` call into the Base Scope's allocator.
|
||||
|
@ -616,26 +596,17 @@ impl VirtualDom {
|
|||
) -> (Mutations<'a>, Mutations<'a>) {
|
||||
let (old, new) = (self.render_vnodes(left), self.render_vnodes(right));
|
||||
|
||||
// let mut machine: DiffState = todo!();
|
||||
// let mut machine = DiffState::new(Mutations::new());
|
||||
let mut create = DiffState::new(&self.scopes);
|
||||
create.stack.scope_stack.push(self.base_scope);
|
||||
create.stack.create_node(old, MountType::Append);
|
||||
create.work(|| false);
|
||||
|
||||
// machine.stack.create_node(old, MountType::Append);
|
||||
let mut edit = DiffState::new(&self.scopes);
|
||||
create.stack.scope_stack.push(self.base_scope);
|
||||
edit.stack.push(DiffInstruction::Diff { old, new });
|
||||
edit.work(&mut || false);
|
||||
|
||||
todo!()
|
||||
|
||||
// machine.work(|| false);
|
||||
// let create_edits = machine.mutations;
|
||||
|
||||
// let mut machine: DiffState = todo!();
|
||||
// // let mut machine = DiffState::new(Mutations::new());
|
||||
|
||||
// machine.stack.push(DiffInstruction::Diff { old, new });
|
||||
|
||||
// machine.work(&mut || false);
|
||||
|
||||
// let edits = machine.mutations;
|
||||
|
||||
// (create_edits, edits)
|
||||
(create.mutations, edit.mutations)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -215,12 +215,12 @@ fn create_components() {
|
|||
})
|
||||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct ChildProps<'a> {
|
||||
children: ScopeChildren<'a>,
|
||||
#[derive(Props, PartialEq)]
|
||||
struct ChildProps {
|
||||
children: Element,
|
||||
}
|
||||
|
||||
fn Child<'a>(cx: Context<'a>, props: &ChildProps<'a>) -> Element {
|
||||
fn Child(cx: Context, props: &ChildProps) -> Element {
|
||||
cx.render(rsx! {
|
||||
h1 {}
|
||||
div { {&props.children} }
|
||||
|
@ -299,21 +299,3 @@ fn anchors() {
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suspended() {
|
||||
todo!()
|
||||
// static App: FC<()> = |cx, props| {
|
||||
// let val = use_suspense(cx, || async {}, |p| todo!());
|
||||
|
||||
// cx.render(rsx! { {val} })
|
||||
// };
|
||||
|
||||
// let mut dom = new_dom(App, ());
|
||||
// let mutations = dom.rebuild();
|
||||
|
||||
// assert_eq!(
|
||||
// mutations.edits,
|
||||
// [CreatePlaceholder { root: 0 }, AppendChildren { many: 1 },]
|
||||
// );
|
||||
}
|
||||
|
|
|
@ -257,12 +257,12 @@ fn many_items_become_fragment() {
|
|||
]
|
||||
);
|
||||
|
||||
// hmmmmmmmmm worried about reusing IDs that we shouldnt be
|
||||
// note: the ID gets reused
|
||||
assert_eq!(
|
||||
change.edits,
|
||||
[
|
||||
Remove { root: 2 },
|
||||
CreatePlaceholder { root: 4 },
|
||||
CreatePlaceholder { root: 3 },
|
||||
ReplaceWith { root: 0, m: 1 },
|
||||
]
|
||||
);
|
||||
|
@ -433,7 +433,7 @@ fn keyed_diffing_order() {
|
|||
let dom = new_dom();
|
||||
|
||||
let left = rsx!(
|
||||
// {(0..5).map(|f| {rsx! { div { key: "{f}" }}})}
|
||||
{(0..5).map(|f| {rsx! { div { key: "{f}" }}})}
|
||||
p {"e"}
|
||||
);
|
||||
let right = rsx!(
|
||||
|
@ -802,22 +802,3 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suspense() {
|
||||
let dom = new_dom();
|
||||
|
||||
todo!()
|
||||
// let edits = dom.create_vnodes(Some(LazyNodes::new(|f| {
|
||||
// use std::cell::{Cell, RefCell};
|
||||
// VNode::Suspended(f.bump().alloc(VSuspended {
|
||||
// task_id: 0,
|
||||
// callback: RefCell::new(None),
|
||||
// dom_id: Cell::new(None),
|
||||
// }))
|
||||
// })));
|
||||
// assert_eq!(
|
||||
// edits.edits,
|
||||
// [CreatePlaceholder { root: 0 }, AppendChildren { many: 1 }]
|
||||
// );
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use dioxus::prelude::Scope;
|
||||
use dioxus::ScopeChildren;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties};
|
||||
use dioxus_core_macro::Props;
|
||||
|
@ -44,7 +43,7 @@ pub struct WebviewWindowProps<'a> {
|
|||
/// focuse me
|
||||
onfocused: &'a dyn FnMut(()),
|
||||
|
||||
children: ScopeChildren<'a>,
|
||||
children: Element,
|
||||
}
|
||||
|
||||
/// A handle to a
|
||||
|
@ -57,7 +56,7 @@ pub struct WebviewWindowProps<'a> {
|
|||
///
|
||||
///
|
||||
///
|
||||
pub fn WebviewWindow((cx, props): Scope<WebviewWindowProps>) -> Element {
|
||||
pub fn WebviewWindow(cx: Context, props: &WebviewWindowProps) -> Element {
|
||||
let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
|
||||
|
||||
cx.use_hook(
|
||||
|
@ -91,7 +90,7 @@ fn syntax_works() {
|
|||
use dioxus_hooks::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
static App: FC<()> = |cx, props| {
|
||||
cx.render(rsx! {
|
||||
// left window
|
||||
WebviewWindow {
|
||||
|
|
|
@ -166,7 +166,7 @@ pub fn run<T: 'static + Send + Sync>(
|
|||
sender.unbounded_send(SchedulerMsg::UiEvent(event)).unwrap();
|
||||
|
||||
if let Some(BridgeEvent::Update(edits)) = rx.blocking_recv() {
|
||||
log::info!("bridge received message {:?}", edits);
|
||||
log::info!("bridge received message");
|
||||
Some(RpcResponse::new_result(req.id.take(), Some(edits)))
|
||||
} else {
|
||||
log::info!("none received message");
|
||||
|
@ -276,7 +276,7 @@ pub(crate) fn launch_vdom_with_tokio<P: Send + 'static>(
|
|||
|
||||
runtime.block_on(async move {
|
||||
let mut vir = VirtualDom::new_with_props_and_scheduler(root, props, sender, receiver);
|
||||
let _ = vir.get_event_sender();
|
||||
let _ = vir.get_scheduler_channel();
|
||||
|
||||
let edits = vir.rebuild();
|
||||
|
||||
|
@ -298,14 +298,13 @@ pub(crate) fn launch_vdom_with_tokio<P: Send + 'static>(
|
|||
// todo: maybe we want to schedule ourselves in
|
||||
// on average though, the virtualdom running natively is stupid fast
|
||||
|
||||
let mut muts = vir.run_with_deadline(|| false);
|
||||
let mut muts = vir.work_with_deadline(|| false);
|
||||
|
||||
log::debug!("finished running with deadline");
|
||||
|
||||
let mut edits = vec![];
|
||||
|
||||
while let Some(edit) = muts.pop() {
|
||||
log::debug!("sending message on channel with edit {:?}", edit);
|
||||
let edit_string = serde_json::to_value(Evt { edits: edit.edits })
|
||||
.expect("serializing edits should never fail");
|
||||
edits.push(edit_string);
|
||||
|
|
1
packages/ssr/index.html
Normal file
1
packages/ssr/index.html
Normal file
|
@ -0,0 +1 @@
|
|||
asd
|
|
@ -14,7 +14,7 @@ use std::fmt::{Display, Formatter};
|
|||
|
||||
use dioxus_core::exports::bumpalo;
|
||||
use dioxus_core::exports::bumpalo::Bump;
|
||||
use dioxus_core::nodes::IntoVNode;
|
||||
use dioxus_core::IntoVNode;
|
||||
use dioxus_core::*;
|
||||
|
||||
/// A memory pool for rendering
|
||||
|
@ -94,7 +94,7 @@ pub fn render_vdom_scope(vdom: &VirtualDom, scope: ScopeId) -> Option<String> {
|
|||
"{:}",
|
||||
TextRenderer {
|
||||
cfg: SsrConfig::default(),
|
||||
root: vdom.get_scope(scope).unwrap().root_node(),
|
||||
root: vdom.get_scope(&scope).unwrap().root_node(),
|
||||
vdom: Some(vdom)
|
||||
}
|
||||
))
|
||||
|
@ -158,6 +158,9 @@ impl<'a> TextRenderer<'a, '_> {
|
|||
}
|
||||
write!(f, "<!-- -->")?;
|
||||
}
|
||||
VNode::Linked(link) => {
|
||||
todo!();
|
||||
}
|
||||
VNode::Element(el) => {
|
||||
if self.cfg.indent {
|
||||
for _ in 0..il {
|
||||
|
@ -244,7 +247,7 @@ impl<'a> TextRenderer<'a, '_> {
|
|||
let idx = vcomp.associated_scope.get().unwrap();
|
||||
|
||||
if let (Some(vdom), false) = (self.vdom, self.cfg.skip_components) {
|
||||
let new_node = vdom.get_scope(idx).unwrap().root_node();
|
||||
let new_node = vdom.get_scope(&idx).unwrap().root_node();
|
||||
self.html_render(new_node, f, il + 1)?;
|
||||
} else {
|
||||
}
|
||||
|
@ -297,18 +300,17 @@ impl SsrConfig {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
use dioxus_html as dioxus_elements;
|
||||
|
||||
static SIMPLE_APP: FC<()> = |(cx, _)| {
|
||||
static SIMPLE_APP: FC<()> = |cx, _| {
|
||||
cx.render(rsx!(div {
|
||||
"hello world!"
|
||||
}))
|
||||
};
|
||||
|
||||
static SLIGHTLY_MORE_COMPLEX: FC<()> = |(cx, _)| {
|
||||
static SLIGHTLY_MORE_COMPLEX: FC<()> = |cx, _| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
title: "About W3Schools"
|
||||
|
@ -327,14 +329,14 @@ mod tests {
|
|||
})
|
||||
};
|
||||
|
||||
static NESTED_APP: FC<()> = |(cx, _)| {
|
||||
static NESTED_APP: FC<()> = |cx, _| {
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
SIMPLE_APP {}
|
||||
}
|
||||
))
|
||||
};
|
||||
static FRAGMENT_APP: FC<()> = |(cx, _)| {
|
||||
static FRAGMENT_APP: FC<()> = |cx, _| {
|
||||
cx.render(rsx!(
|
||||
div { "f1" }
|
||||
div { "f2" }
|
||||
|
@ -390,7 +392,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn styles() {
|
||||
static STLYE_APP: FC<()> = |(cx, _)| {
|
||||
static STLYE_APP: FC<()> = |cx, _| {
|
||||
cx.render(rsx! {
|
||||
div { color: "blue", font_size: "46px" }
|
||||
})
|
||||
|
|
|
@ -7,17 +7,12 @@
|
|||
//! - tests to ensure dyn_into works for various event types.
|
||||
//! - Partial delegation?>
|
||||
|
||||
use dioxus_core::{
|
||||
events::{KeyCode, UserEvent},
|
||||
mutations::NodeRefMutation,
|
||||
scheduler::SchedulerMsg,
|
||||
DomEdit, ElementId, ScopeId,
|
||||
};
|
||||
use dioxus_core::{DomEdit, ElementId, SchedulerMsg, ScopeId, UserEvent};
|
||||
use fxhash::FxHashMap;
|
||||
use std::{any::Any, fmt::Debug, rc::Rc, sync::Arc};
|
||||
use std::{any::Any, fmt::Debug, rc::Rc};
|
||||
use wasm_bindgen::{closure::Closure, JsCast};
|
||||
use web_sys::{
|
||||
Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
|
||||
CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
|
||||
HtmlOptionElement, HtmlTextAreaElement, Node, NodeList,
|
||||
};
|
||||
|
||||
|
@ -55,7 +50,7 @@ impl WebsysDom {
|
|||
let document = load_document();
|
||||
|
||||
let mut nodes = NodeSlab::new(2000);
|
||||
let mut listeners = FxHashMap::default();
|
||||
let listeners = FxHashMap::default();
|
||||
|
||||
// re-hydrate the page - only supports one virtualdom per page
|
||||
if cfg.hydrate {
|
||||
|
@ -90,17 +85,17 @@ impl WebsysDom {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn apply_refs(&mut self, refs: &[NodeRefMutation]) {
|
||||
for item in refs {
|
||||
if let Some(bla) = &item.element {
|
||||
let node = self.nodes[item.element_id.as_u64() as usize]
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.clone();
|
||||
bla.set(Box::new(node)).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub fn apply_refs(&mut self, refs: &[NodeRefMutation]) {
|
||||
// for item in refs {
|
||||
// if let Some(bla) = &item.element {
|
||||
// let node = self.nodes[item.element_id.as_u64() as usize]
|
||||
// .as_ref()
|
||||
// .unwrap()
|
||||
// .clone();
|
||||
// bla.set(Box::new(node)).unwrap();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn process_edits(&mut self, edits: &mut Vec<DomEdit>) {
|
||||
for edit in edits.drain(..) {
|
||||
|
@ -309,8 +304,8 @@ impl WebsysDom {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_event_listener(&mut self, event: &str, root: u64) {
|
||||
// todo!()
|
||||
fn remove_event_listener(&mut self, _event: &str, _root: u64) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_text(&mut self, text: &str, root: u64) {
|
||||
|
@ -489,8 +484,9 @@ unsafe impl Sync for DioxusWebsysEvent {}
|
|||
// todo: some of these events are being casted to the wrong event type.
|
||||
// We need tests that simulate clicks/etc and make sure every event type works.
|
||||
fn virtual_event_from_websys_event(event: web_sys::Event) -> Box<dyn Any + Send> {
|
||||
use crate::events::*;
|
||||
use dioxus_core::events::on::*;
|
||||
use dioxus_html::on::*;
|
||||
use dioxus_html::KeyCode;
|
||||
// use dioxus_core::events::on::*;
|
||||
match event.type_().as_str() {
|
||||
"copy" | "cut" | "paste" => Box::new(ClipboardEvent {}),
|
||||
"compositionend" | "compositionstart" | "compositionupdate" => {
|
||||
|
@ -682,15 +678,6 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
|
|||
|
||||
let typ = event.type_();
|
||||
|
||||
// TODO: clean this up
|
||||
if cfg!(debug_assertions) {
|
||||
let attrs = target.attributes();
|
||||
for x in 0..attrs.length() {
|
||||
let attr: Attr = attrs.item(x).unwrap();
|
||||
// log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
|
||||
}
|
||||
}
|
||||
|
||||
use anyhow::Context;
|
||||
|
||||
// The error handling here is not very descriptive and needs to be replaced with a zero-cost error system
|
||||
|
@ -716,7 +703,8 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
|
|||
name: event_name_from_typ(&typ),
|
||||
event: virtual_event_from_websys_event(event.clone()),
|
||||
mounted_dom_id: Some(ElementId(real_id as usize)),
|
||||
scope: ScopeId(triggered_scope as usize),
|
||||
scope_id: ScopeId(triggered_scope as usize),
|
||||
priority: dioxus_core::EventPriority::Medium,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
//! Ported events into Dioxus Synthetic Event system
|
||||
|
||||
use dioxus_core::events::on::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{Event, UiEvent};
|
|
@ -57,8 +57,8 @@ use std::rc::Rc;
|
|||
pub use crate::cfg::WebConfig;
|
||||
use crate::dom::load_document;
|
||||
use cache::intern_cached_strings;
|
||||
use dioxus::prelude::Properties;
|
||||
use dioxus::virtual_dom::VirtualDom;
|
||||
use dioxus::SchedulerMsg;
|
||||
use dioxus::VirtualDom;
|
||||
pub use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::FC;
|
||||
use futures_util::FutureExt;
|
||||
|
@ -66,7 +66,6 @@ use futures_util::FutureExt;
|
|||
mod cache;
|
||||
mod cfg;
|
||||
mod dom;
|
||||
mod events;
|
||||
mod nodeslab;
|
||||
mod ric_raf;
|
||||
|
||||
|
@ -144,9 +143,10 @@ pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg:
|
|||
|
||||
let root_el = load_document().get_element_by_id(&cfg.rootname).unwrap();
|
||||
|
||||
let tasks = dom.get_event_sender();
|
||||
let tasks = dom.get_scheduler_channel();
|
||||
|
||||
let sender_callback = Rc::new(move |event| tasks.unbounded_send(event).unwrap());
|
||||
let sender_callback: Rc<dyn Fn(SchedulerMsg)> =
|
||||
Rc::new(move |event| tasks.unbounded_send(event).unwrap());
|
||||
|
||||
let mut websys_dom = dom::WebsysDom::new(root_el, cfg, sender_callback);
|
||||
|
||||
|
@ -170,13 +170,12 @@ pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg:
|
|||
let mut deadline = work_loop.wait_for_idle_time().await;
|
||||
|
||||
// run the virtualdom work phase until the frame deadline is reached
|
||||
let mutations = dom.run_with_deadline(|| (&mut deadline).now_or_never().is_some());
|
||||
let mutations = dom.work_with_deadline(|| (&mut deadline).now_or_never().is_some());
|
||||
|
||||
// wait for the animation frame to fire so we can apply our changes
|
||||
work_loop.wait_for_raf().await;
|
||||
|
||||
for mut edit in mutations {
|
||||
// log::debug!("edits are {:#?}", edit);
|
||||
// actually apply our changes during the animation frame
|
||||
websys_dom.process_edits(&mut edit.edits);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue