docs: examples
This commit is contained in:
1 parent
818043e5e4
commit
d9e6d0925b
33 files changed
+732
-152
No files matched your search
@@ -30,6 +30,7 @@ split-debuginfo = "unpacked"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
futures = "0.3.15"
|
futures = "0.3.15"
|
||||||
|
log = "0.4.14"
|
||||||
# For the tide ssr examples
|
# For the tide ssr examples
|
||||||
# async-std = { version="1.9.0", features=["attributes"] }
|
# async-std = { version="1.9.0", features=["attributes"] }
|
||||||
# tide = { version="0.16.0" }
|
# tide = { version="0.16.0" }
|
||||||
|
|||||||
+46
-25
@@ -1,29 +1,50 @@
|
|||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
Most of these examples are run through webview so you don't need the dioxus cli installed to preview the functionality. Anything labeled `_web` will need to be built with the Dioxus CLI to preview features that only a native bundle can handle.
|
Most of these examples are run through webview so you don't need the dioxus cli installed to preview the functionality.
|
||||||
|
|
||||||
List of examples:
|
These examples are fully-fledged micro apps. They can be ran with the `cargo run --example XYZ`
|
||||||
|
|
||||||
| Example | What it does |
|
| Example | What it does | Status |
|
||||||
| --------------------------------------- | ------------ |
|
| --------------------------------------------------- | ------------------------------------------- | ------ |
|
||||||
| [The basics](./basics.rs) | this does |
|
| [The basics](./basics.rs) | A few basic examples to preview Dioxus | 🛠 |
|
||||||
| [fine grained reactivity](./signals.rs) | this does |
|
| [fine grained reactivity](./signals.rs) | Escape `diffing` by writing values directly | 🛠 |
|
||||||
| Global State Management | this does |
|
| [Global State Management](./statemanagement.rs) | Share state between components | 🛠 |
|
||||||
| Virtual Refs | this does |
|
| [Virtual Refs]() | Cross-platform imperative elements | 🛠 |
|
||||||
| Inline Styles | this does |
|
| [Inline Styles](./inline-styles.rs) | Define styles for elements inline | 🛠 |
|
||||||
| Conditional Rendering | this does |
|
| [Conditional Rendering](./conditional-rendering.rs) | Hide/Show elements using conditionals | ✅ |
|
||||||
| Maps/Iterators | this does |
|
|
||||||
| Render To string | this does |
|
These examples are not necessarily meant to be run, but rather serve as a reference for the given functionality.
|
||||||
| Component Children | this does |
|
|
||||||
| Function Driven children | this does |
|
| Example | What it does | Status |
|
||||||
| Memoization | this does |
|
| --------------------------------------------------- | ----------------------------------------------- | ------ |
|
||||||
| Borrowed Data | this does |
|
| [The basics](./basics.rs) | A few basic examples to preview Dioxus | 🛠 |
|
||||||
| Fragments | this does |
|
| [fine grained reactivity](./signals.rs) | Escape `diffing` by writing values directly | 🛠 |
|
||||||
| Null/None Components | this does |
|
| [Global State Management](./statemanagement.rs) | Share state between components | 🛠 |
|
||||||
| Spread Pattern for props | this does |
|
| [Virtual Refs]() | Cross-platform imperative elements | 🛠 |
|
||||||
| Controlled Inputs | this does |
|
| [Inline Styles](./inline-styles.rs) | Define styles for elements inline | 🛠 |
|
||||||
| Custom Elements | this does |
|
| [Conditional Rendering](./conditional-rendering.rs) | Hide/Show elements using conditionals | ✅ |
|
||||||
| Testing And debugging | this does |
|
| [Maps/Iterators](./iterators.rs) | Use iterators in the rsx! macro | 🛠 |
|
||||||
| Asynchronous Data | this does |
|
| [Render To string](./tostring.rs) | Render a mounted virtualdom to a string | 🛠 |
|
||||||
| Fiber/Scheduled Rendering | this does |
|
| [Component Children](./children.rs) | Pass children into child components | 🛠 |
|
||||||
| CSS Compiled Styles | this does |
|
| [Function Driven children]() | Pass functions to make VNodes | 🛠 |
|
||||||
|
| [Memoization & Borrowed Data](./memo.rs) | Suppress renders, borrow from parents | ✅ |
|
||||||
|
| [Fragments](./fragments.rs) | Support root-less element groups | ✅ |
|
||||||
|
| [Null/None Components](./empty.rs) | Return nothing! | 🛠 |
|
||||||
|
| [Spread Pattern for props](./spreadpattern.rs) | Manually specify and override props | ✅ |
|
||||||
|
| [Controlled Inputs](./controlled-inputs.rs) | this does | 🛠 |
|
||||||
|
| [Custom Elements]() | Define custom elements | 🛠 |
|
||||||
|
| [Web Components]() | Custom elements to interface with WebComponents | 🛠 |
|
||||||
|
| [Testing And debugging]() | this does | 🛠 |
|
||||||
|
| [Asynchronous Data]() | Using suspense to wait for data | 🛠 |
|
||||||
|
| [Fiber/Scheduled Rendering]() | this does | 🛠 |
|
||||||
|
| [CSS Compiled Styles]() | this does | 🛠 |
|
||||||
|
| [Anti-patterns](./antipatterns.rs) | A collection of discouraged patterns | ✅ |
|
||||||
|
| [Complete rsx reference](./rsx_usage.rs) | A complete reference for all rsx! usage | ✅ |
|
||||||
|
| [Event Listeners](./listener.rs) | Attach closures to events on elements | ✅ |
|
||||||
|
|
||||||
|
These web-specific examples must be run with `dioxus-cli` using `dioxus develop --example XYZ`
|
||||||
|
|
||||||
|
| Example | What it does |
|
||||||
|
| ------- | ------------ |
|
||||||
|
| asd | this does |
|
||||||
|
| asd | this does |
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#![allow(unused, non_upper_case_globals)]
|
|
||||||
|
|
||||||
use dioxus_core::prelude::*;
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
|
|
||||||
static Example: FC<()> = |cx| {
|
|
||||||
let (name, set_name) = use_state(&cx, || "...?");
|
|
||||||
|
|
||||||
cx.render(rsx!(
|
|
||||||
div {
|
|
||||||
h1 { "Hello, {name}" }
|
|
||||||
// look ma - we can rsx! and html! together
|
|
||||||
{["jack", "jill"].iter().map(|f| html!(<button onclick={move |_| set_name(f)}> "{f}" </button>))}
|
|
||||||
}
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn render<'src, 'a, F: for<'b> FnOnce(&'b NodeFactory<'src>) -> VNode<'src> + 'src + 'a, P>(
|
|
||||||
cx: &'a Context<'src, P>,
|
|
||||||
lazy_nodes: LazyNodes<'src, F>,
|
|
||||||
) -> VNode<'src> {
|
|
||||||
cx.render(lazy_nodes)
|
|
||||||
}
|
|
||||||
@@ -21,10 +21,10 @@ fn main() {}
|
|||||||
/// Antipattern: Iterators without keys
|
/// Antipattern: Iterators without keys
|
||||||
/// -----------------------------------
|
/// -----------------------------------
|
||||||
///
|
///
|
||||||
/// This is considered an anti-pattern for performance reasons. Dioxus must diff your current and old layout and must
|
/// This is considered an anti-pattern for performance reasons. Dioxus will diff your current and old layout and must
|
||||||
/// take a slower path if it can't correlate old elements with new elements. Lists are particularly susceptible to the
|
/// take a slower path if it can't correlate old elements with new elements. Lists are particularly susceptible to the
|
||||||
/// "slow" path, so you're strongly encouraged to provide a unique ID stable between renders. Additionally, providing
|
/// "slow" path, so you're strongly encouraged to provide a unique ID stable between renders. Additionally, providing
|
||||||
/// the *wrong* keys is even worse. Keys should be:
|
/// the *wrong* keys is even worse - props might be assigned to the wrong components! Keys should be:
|
||||||
/// - Unique
|
/// - Unique
|
||||||
/// - Stable
|
/// - Stable
|
||||||
/// - Predictable
|
/// - Predictable
|
||||||
@@ -39,7 +39,7 @@ static AntipatternNoKeys: FC<NoKeysProps> = |cx| {
|
|||||||
rsx!(in cx, ul {
|
rsx!(in cx, ul {
|
||||||
{cx.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
|
{cx.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
|
||||||
});
|
});
|
||||||
// Like this:
|
// RIGHT: Like this:
|
||||||
rsx!(in cx, ul {
|
rsx!(in cx, ul {
|
||||||
{cx.data.iter().map(|(k, v)| rsx!(li { key: "{k}", "List item: {v}" }))}
|
{cx.data.iter().map(|(k, v)| rsx!(li { key: "{k}", "List item: {v}" }))}
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
//! Example: Children
|
||||||
|
//! -----------------
|
||||||
|
//!
|
||||||
|
//! Dioxus supports passing children in from the parent. These children are allocated in the parent and just forced
|
||||||
|
//! into the child. Components that pass in children may not be safely memoized, though in practice its rare for a
|
||||||
|
//! change in a parent to not result in a different set of children.
|
||||||
|
//!
|
||||||
|
//! In Dioxus, children can *only be a list*. Unlike React, you cannot pass in functions or arbitrary data. This is
|
||||||
|
//! partially a limitaiton in having static types, but is rather intentional to encourage the use of attributes where
|
||||||
|
//! arbitrary child data might normally be used. Check out the `function driven children` example for how to adopt your
|
||||||
|
//! React pattern for Dioxus' semantics.
|
||||||
|
//!
|
||||||
|
//! Dioxus will let you use the `children` method more than once - and it's semantically *okay* - but you'll likely
|
||||||
|
//! ruin your page if you try to clone elements in this way. Under the hood, Dioxus shares a "mounted ID" for each node,
|
||||||
|
//! and mounting the same VNode in two places will overwrite the first mounted ID. This will likely lead to dead elements.
|
||||||
|
//!
|
||||||
|
//! In the future, this might become a runtime error, so consider it an error today.
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static App: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
Banner {
|
||||||
|
p { "Some Content1" }
|
||||||
|
}
|
||||||
|
Banner {
|
||||||
|
p { "Some Content2" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
static Banner: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
h1 { "This is a great banner!" }
|
||||||
|
div { class: "content"
|
||||||
|
{cx.children()}
|
||||||
|
}
|
||||||
|
footer { "Wow, what a great footer" }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
//! Example: Conditional Rendering
|
||||||
|
//! ------------------------------
|
||||||
|
//!
|
||||||
|
//! This example shows how to hide or show elements using conditional rendering.
|
||||||
|
//!
|
||||||
|
//! Often times you might want to display a different UI given some sort of condition. This is called "conditonal rendering".
|
||||||
|
//! In Dioxus, you can perform conditional rendering with optionals or matching.
|
||||||
|
//!
|
||||||
|
//! The rsx! and html! macro accepts anything that is `IntoIter<Item = impl IntoVnode>`. Options and Results both implement
|
||||||
|
//! IntoIter for impl VNode, so you can use option/result for conditional rendering.
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
// Convert a boolean conditional into a hide/show
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps {
|
||||||
|
should_show: bool,
|
||||||
|
}
|
||||||
|
static Example: FC<MyProps> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
{cx.should_show.then(|| rsx!{
|
||||||
|
h1 { "showing the title!" }
|
||||||
|
})}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert a boolean conditional into an either/or
|
||||||
|
// Because rsx! is lazy (produces a closure), we cannot use it in two branch arms. To use it in matching/branching, we
|
||||||
|
// must render it.
|
||||||
|
//
|
||||||
|
// Dioxus will let you render any `LazyNodes` into a `VNode` with `cx.render`. `rsx!` also supports the `in cx` syntax
|
||||||
|
// which will do essentially the same thing as `cx.render`.
|
||||||
|
//
|
||||||
|
// In short:
|
||||||
|
// `rsx!(in cx, ...)` is shorthand for `cx.render(rsx!(...))`
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps1 {
|
||||||
|
should_show: bool,
|
||||||
|
}
|
||||||
|
static Example1: FC<MyProps1> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
// With matching
|
||||||
|
{match cx.should_show {
|
||||||
|
true => cx.render(rsx!(div {"it is true!"})),
|
||||||
|
false => rsx!(in cx, div {"it is false!"}),
|
||||||
|
}}
|
||||||
|
|
||||||
|
// or with just regular conditions
|
||||||
|
{if cx.should_show {
|
||||||
|
rsx!(in cx, div {"it is true!"})
|
||||||
|
} else {
|
||||||
|
rsx!(in cx, div {"it is false!"})
|
||||||
|
}}
|
||||||
|
|
||||||
|
// or with optional chaining
|
||||||
|
{
|
||||||
|
cx.should_show
|
||||||
|
.then(|| rsx!(in cx, div {"it is false!"}))
|
||||||
|
.unwrap_or_else(|| rsx!(in cx, div {"it is false!"}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Matching can be expanded
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum Color {
|
||||||
|
Green,
|
||||||
|
Yellow,
|
||||||
|
Red,
|
||||||
|
}
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps2 {
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
static Example2: FC<MyProps2> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
{match cx.color {
|
||||||
|
Color::Green => rsx!(in cx, div {"it is Green!"}),
|
||||||
|
Color::Yellow => rsx!(in cx, div {"it is Yellow!"}),
|
||||||
|
Color::Red => rsx!(in cx, div {"it is Red!"}),
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//! Example: Null/None Children
|
||||||
|
//! ---------------------------
|
||||||
|
//!
|
||||||
|
//! This is a simple pattern that allows you to return no elements!
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
//! Example: Fragments
|
||||||
|
//! ------------------
|
||||||
|
//!
|
||||||
|
//! Dioxus can return multiple elements without a container through the use of the VNode called a "Fragment". Fragments do not
|
||||||
|
//! have a mounted root and are inserted inline with their siblings. There are three ways of creating fragments as outlined
|
||||||
|
//! in the examples below:
|
||||||
|
//! - By returning multiple elements in Rsx!
|
||||||
|
//! - By using the `Fragment` component
|
||||||
|
//! - By using the fragment() method on the node factory
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
// Returning multiple elements with rsx! or html!
|
||||||
|
static Example1: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
h1 { }
|
||||||
|
h2 { }
|
||||||
|
h3 { }
|
||||||
|
// {}
|
||||||
|
// "hello world"
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using the Fragment component
|
||||||
|
static Example2: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
Fragment {
|
||||||
|
div {}
|
||||||
|
div {}
|
||||||
|
"asd"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using the `fragment` method on the NodeFactory
|
||||||
|
static Example3: FC<()> = |cx| {
|
||||||
|
cx.render(LazyNodes::new(move |fac: &NodeFactory| {
|
||||||
|
fac.fragment_builder(None, |list| {
|
||||||
|
list.add_child(fac.text(format_args!("A")))
|
||||||
|
.add_child(fac.text(format_args!("B")))
|
||||||
|
.finish()
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
//! Example: Listeners
|
||||||
|
//! ------------------
|
||||||
|
//!
|
||||||
|
//! This example demonstrates the various ways listeners may be used in Dioxus.
|
||||||
|
//! Listeners may be at most `FnMut` - but not `FnOnce`.
|
||||||
|
//! Listeners may borrow the lifetime of cx (children and hooks), but not of local (stack) data.
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
/// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name.
|
||||||
|
static ButtonList: FC<()> = |cx| {
|
||||||
|
let (name, set_name) = use_state(&cx, || "...?");
|
||||||
|
|
||||||
|
let names = ["jack", "jill", "john", "jane"]
|
||||||
|
.iter()
|
||||||
|
.map(move |n| rsx!(button { onclick: move |_| set_name(n), "{n}" }));
|
||||||
|
|
||||||
|
cx.render(rsx!(
|
||||||
|
div {
|
||||||
|
h1 { "Hello, {name}" }
|
||||||
|
{names}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This shows how listeners may be without a visible change in the display.
|
||||||
|
/// Check the console.
|
||||||
|
static NonUpdatingEvents: FC<()> = |cx| {
|
||||||
|
rsx!(in cx, div {
|
||||||
|
button {
|
||||||
|
onclick: move |_| log::info!("Did not cause any updates!")
|
||||||
|
"Click me to log!"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
static DisablePropogation: FC<()> = |cx| {
|
||||||
|
rsx!(in cx,
|
||||||
|
div {
|
||||||
|
onclick: move |_| log::info!("event propogated to the div!")
|
||||||
|
button {
|
||||||
|
onclick: move |evt| {
|
||||||
|
log::info!("Button will allow propogation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
//! Example: Memoization
|
||||||
|
//! --------------------
|
||||||
|
//!
|
||||||
|
//! This example showcases how memoization works in Dioxus.
|
||||||
|
//!
|
||||||
|
//! Memoization is the process in which Dioxus skips diffing child components if their props don't change.
|
||||||
|
//! In React, components are never memoized unless wrapped in `memo` or configured with `shouldComponentUpdate`.
|
||||||
|
//!
|
||||||
|
//! Due to the safety guarantees of Rust, we can automatically memoize components in some circumstances. Whenever a
|
||||||
|
//! component's properties are valid for the `'static` lifetime, Dioxus will automatically compare the props before
|
||||||
|
//! diffing the component. If the props don't change (according to PartialEq), the component will not be re-rendered.
|
||||||
|
//!
|
||||||
|
//! However, if the props use some generics or borrow from their parent, then Dioxus can't safely supress updates,
|
||||||
|
//! and is forced to render the child. If you think that this behavior is wrong for your usecase, you can implement
|
||||||
|
//! the memo method yourself, but beware, doing so is UNSAFE and may cause issues if you do it wrong.
|
||||||
|
//!
|
||||||
|
//! If you want to gain that little bit extra performance, consider using global state management, signals, or
|
||||||
|
//! memoized collections like im-rc which are designed for this use case.
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
// By default, components with no props are always memoized.
|
||||||
|
// A props of () is considered empty.
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div { "100% memoized!" }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// These props do not borrow any content, and therefore can be safely memoized.
|
||||||
|
// However, the parent *must* create a new string on every render.
|
||||||
|
// Notice how these props implement PartialEq - this is required for 'static props
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps1 {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
static Example1: FC<MyProps1> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div { "100% memoized! {cx.name}" }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// These props do not borrow any content, and therefore can be safely memoized.
|
||||||
|
// In contrast with the `String` example, these props use `Rc<str>` which operates similar to strings in JavaScript.
|
||||||
|
// These strings cannot be modified, but may be cheaply shared in many places without issue.
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps2 {
|
||||||
|
name: std::rc::Rc<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static Example2: FC<MyProps2> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div { "100% memoized! {cx.name}" }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// These props *do* borrow any content, and therefore cannot be safely memoized!.
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps3<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
}
|
||||||
|
// We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
|
||||||
|
// Using the `static Example: FC<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
|
||||||
|
// not exactly be what you want
|
||||||
|
fn Example3<'a>(cx: Context<'a, MyProps3<'a>>) -> VNode {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div { "Not memoized! {cx.name}" }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// These props *do* borrow any content, and therefore cannot be safely memoized!.
|
||||||
|
// However, they cannot be compared, so we don't need the PartialEq flag.
|
||||||
|
#[derive(Props)]
|
||||||
|
struct MyProps4<'a> {
|
||||||
|
onhandle: &'a dyn Fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
|
||||||
|
fn Example4<'a>(cx: Context<'a, MyProps4<'a>>) -> VNode {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div { "Not memoized!", onclick: move |_| (cx.onhandle)() }
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod iterator;
|
||||||
|
mod memo;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
//! Example: Spread pattern for Components
|
||||||
|
//! --------------------------------------
|
||||||
|
//!
|
||||||
|
//! Dioxus supports the "spread" pattern for manually building a components properties. This is useful when props
|
||||||
|
//! are passed down from a parent, or it's more ergonomic to construct props from outside the rsx! macro.
|
||||||
|
//!
|
||||||
|
//! To use the spread pattern, simply pass ".." followed by a Rust epxression. This pattern also supports overriding
|
||||||
|
//! values, using the manual props as the base and then modifying fields specified with non-spread attributes.
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static App: FC<()> = |cx| {
|
||||||
|
let props = MyProps {
|
||||||
|
count: 0,
|
||||||
|
live: true,
|
||||||
|
name: "Dioxus",
|
||||||
|
};
|
||||||
|
cx.render(rsx! {
|
||||||
|
Example { ..props, count: 10, div {"child"} }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Props)]
|
||||||
|
struct MyProps {
|
||||||
|
count: u32,
|
||||||
|
live: bool,
|
||||||
|
name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
static Example: FC<MyProps> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
h1 { "Hello, {cx.name}"}
|
||||||
|
h3 {"Are we alive? {cx.live}"}
|
||||||
|
p {"Count is {cx.count}"}
|
||||||
|
{ cx.children() }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
File renamed without changes.
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
static Example: FC<()> = |cx| {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//! Example: Web Components
|
||||||
|
//! -----------------------
|
||||||
|
//!
|
||||||
|
//! Web components are a flavor of html elements that can be user-defined.
|
||||||
|
//! See: https://www.webcomponents.org for more information.
|
||||||
|
//!
|
||||||
|
//! Users who use webcomponents typically don't use Dioxus. However, if you would like to use webcomponents in Dioxus,
|
||||||
|
//! you can easily create a new custom element with compile-time correct wrappers around the webcomponent.
|
||||||
|
//!
|
||||||
|
//! We don't support building new webcomponents with Dioxus, however.
|
||||||
|
//!
|
||||||
|
|
||||||
|
use dioxus::{builder::ElementBuilder, prelude::NodeFactory};
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
struct MyEle<'a, 'b> {
|
||||||
|
el: ElementBuilder<'a, 'b>,
|
||||||
|
fac: &'b NodeFactory<'a>,
|
||||||
|
}
|
||||||
@@ -120,7 +120,7 @@ static Example: FC<()> = |cx| {
|
|||||||
{if true {
|
{if true {
|
||||||
rsx!(in cx, h1 {"Top text"})
|
rsx!(in cx, h1 {"Top text"})
|
||||||
} else {
|
} else {
|
||||||
cx.render(rsx!( h1 {"Bottom text"}))
|
rsx!(in cx, h1 {"Bottom text"})
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// returning "None" is a bit noisy... but rare in practice
|
// returning "None" is a bit noisy... but rare in practice
|
||||||
@@ -168,7 +168,13 @@ static Example: FC<()> = |cx| {
|
|||||||
rsx!(Taller { ..props })
|
rsx!(Taller { ..props })
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// Can take children
|
// Spreading can also be overridden manually
|
||||||
|
Taller {
|
||||||
|
..TallerProps { a: "ballin!" }
|
||||||
|
a: "not ballin!"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can take children too!
|
||||||
Taller { a: "asd", div {"hello world!"} }
|
Taller { a: "asd", div {"hello world!"} }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+28
-23
@@ -1,26 +1,31 @@
|
|||||||
//! A Showcase of all the useful examples
|
//! Example: Reference Showcase
|
||||||
//!
|
//! ---------------------------
|
||||||
//!
|
|
||||||
//!
|
//!
|
||||||
|
//! This example provides a cute interface for browsing the reference examples.
|
||||||
|
|
||||||
fn main() {
|
mod reference {
|
||||||
use_css_consumer(&cx, "mystyle");
|
mod antipatterns;
|
||||||
|
mod basics;
|
||||||
// at the global head of the app
|
mod children;
|
||||||
use_css_provider(&cx, |cfg| {});
|
mod conditional_rendering;
|
||||||
use_recoil_provider(&cx, |cfg| {});
|
mod controlled_inputs;
|
||||||
|
mod custom_elements;
|
||||||
let recoil = use_recoil_api(&cx, |_| {});
|
mod empty;
|
||||||
use_websocket_connection(&cx, move |cfg| {
|
mod fiber;
|
||||||
cfg.on_receive(move |event| match event.data::<Msg>() {
|
mod fragments;
|
||||||
Ok(msg) => match msg {
|
mod global_css;
|
||||||
a => recoil.set(&ATOM, 10),
|
mod inline_styles;
|
||||||
c => recoil.set(&ATOM, 20),
|
mod iterators;
|
||||||
_ => {}
|
mod listener;
|
||||||
},
|
mod memo;
|
||||||
Err(e) => {}
|
mod noderefs;
|
||||||
});
|
mod signals;
|
||||||
cfg.on_close(move |event| {});
|
mod spreadpattern;
|
||||||
cfg.on_open(move |event| {});
|
mod statemanagement;
|
||||||
});
|
mod suspense;
|
||||||
|
mod testing;
|
||||||
|
mod tostring;
|
||||||
|
mod webcomponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -80,33 +80,46 @@ impl ToTokens for Component {
|
|||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
let name = &self.name;
|
let name = &self.name;
|
||||||
|
|
||||||
let using_manual_override = self.manual_props.is_some();
|
|
||||||
|
|
||||||
let mut builder = {
|
|
||||||
match &self.manual_props {
|
|
||||||
Some(manual_props) => quote! { #manual_props },
|
|
||||||
None => quote! { fc_to_builder(#name) },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut has_key = None;
|
let mut has_key = None;
|
||||||
|
|
||||||
for field in &self.body {
|
let builder = match &self.manual_props {
|
||||||
if field.name.to_string() == "key" {
|
Some(manual_props) => {
|
||||||
has_key = Some(field);
|
let mut toks = quote! {
|
||||||
} else {
|
let mut __manual_props = #manual_props;
|
||||||
match using_manual_override {
|
};
|
||||||
true => panic!("Currently we don't support manual props and prop fields. Choose either manual props or prop fields"),
|
for field in &self.body {
|
||||||
false => builder.append_all(quote! {#field}),
|
if field.name.to_string() == "key" {
|
||||||
|
has_key = Some(field);
|
||||||
|
} else {
|
||||||
|
let name = &field.name;
|
||||||
|
let val = &field.content;
|
||||||
|
toks.append_all(quote! {
|
||||||
|
__manual_props.#name = #val;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
toks.append_all(quote! {
|
||||||
|
__manual_props
|
||||||
|
});
|
||||||
|
quote! {{
|
||||||
|
#toks
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
|
let mut toks = quote! { fc_to_builder(#name) };
|
||||||
if !using_manual_override {
|
for field in &self.body {
|
||||||
builder.append_all(quote! {
|
if field.name.to_string() == "key" {
|
||||||
.build()
|
has_key = Some(field);
|
||||||
});
|
} else {
|
||||||
}
|
toks.append_all(quote! {#field})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toks.append_all(quote! {
|
||||||
|
.build()
|
||||||
|
});
|
||||||
|
toks
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let key_token = match has_key {
|
let key_token = match has_key {
|
||||||
Some(field) => {
|
Some(field) => {
|
||||||
|
|||||||
+61
-52
@@ -4,7 +4,7 @@
|
|||||||
//! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
|
//! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
|
||||||
//! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
|
//! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::{ops::Deref, rc::Rc};
|
||||||
|
|
||||||
use crate::{innerlude::ScopeIdx, virtual_dom::RealDomNode};
|
use crate::{innerlude::ScopeIdx, virtual_dom::RealDomNode};
|
||||||
|
|
||||||
@@ -28,21 +28,21 @@ impl EventTrigger {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum VirtualEvent {
|
pub enum VirtualEvent {
|
||||||
// Real events
|
// Real events
|
||||||
ClipboardEvent(Rc<dyn on::ClipboardEvent>),
|
ClipboardEvent(on::ClipboardEvent),
|
||||||
CompositionEvent(Rc<dyn on::CompositionEvent>),
|
CompositionEvent(on::CompositionEvent),
|
||||||
KeyboardEvent(Rc<dyn on::KeyboardEvent>),
|
KeyboardEvent(on::KeyboardEvent),
|
||||||
FocusEvent(Rc<dyn on::FocusEvent>),
|
FocusEvent(on::FocusEvent),
|
||||||
FormEvent(Rc<dyn on::FormEvent>),
|
FormEvent(on::FormEvent),
|
||||||
SelectionEvent(Rc<dyn on::SelectionEvent>),
|
SelectionEvent(on::SelectionEvent),
|
||||||
TouchEvent(Rc<dyn on::TouchEvent>),
|
TouchEvent(on::TouchEvent),
|
||||||
UIEvent(Rc<dyn on::UIEvent>),
|
UIEvent(on::UIEvent),
|
||||||
WheelEvent(Rc<dyn on::WheelEvent>),
|
WheelEvent(on::WheelEvent),
|
||||||
MediaEvent(Rc<dyn on::MediaEvent>),
|
MediaEvent(on::MediaEvent),
|
||||||
AnimationEvent(Rc<dyn on::AnimationEvent>),
|
AnimationEvent(on::AnimationEvent),
|
||||||
TransitionEvent(Rc<dyn on::TransitionEvent>),
|
TransitionEvent(on::TransitionEvent),
|
||||||
ToggleEvent(Rc<dyn on::ToggleEvent>),
|
ToggleEvent(on::ToggleEvent),
|
||||||
MouseEvent(Rc<dyn on::MouseEvent>),
|
MouseEvent(on::MouseEvent),
|
||||||
PointerEvent(Rc<dyn on::PointerEvent>),
|
PointerEvent(on::PointerEvent),
|
||||||
|
|
||||||
// Whenever a task is ready (complete) Dioxus produces this "FiberEvent"
|
// Whenever a task is ready (complete) Dioxus produces this "FiberEvent"
|
||||||
FiberEvent { task_id: u16 },
|
FiberEvent { task_id: u16 },
|
||||||
@@ -75,12 +75,21 @@ pub mod on {
|
|||||||
use super::VirtualEvent;
|
use super::VirtualEvent;
|
||||||
|
|
||||||
macro_rules! event_directory {
|
macro_rules! event_directory {
|
||||||
( $( $eventdata:ident: [ $( $name:ident )* ]; )* ) => {
|
( $( $eventdata:ident($wrapper:ident): [ $( $name:ident )* ]; )* ) => {
|
||||||
$(
|
$(
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct $wrapper(Rc<dyn $eventdata>);
|
||||||
|
impl Deref for $wrapper {
|
||||||
|
type Target = Rc<dyn $eventdata>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(
|
$(
|
||||||
pub fn $name<'a>(
|
pub fn $name<'a>(
|
||||||
c: &'_ NodeFactory<'a>,
|
c: &'_ NodeFactory<'a>,
|
||||||
callback: impl Fn(Rc<dyn $eventdata>) + 'a,
|
callback: impl Fn($wrapper) + 'a,
|
||||||
) -> Listener<'a> {
|
) -> Listener<'a> {
|
||||||
let bump = &c.bump();
|
let bump = &c.bump();
|
||||||
Listener {
|
Listener {
|
||||||
@@ -88,7 +97,7 @@ pub mod on {
|
|||||||
mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
|
mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
|
||||||
scope: c.scope_ref.arena_idx,
|
scope: c.scope_ref.arena_idx,
|
||||||
callback: bump.alloc(move |evt: VirtualEvent| match evt {
|
callback: bump.alloc(move |evt: VirtualEvent| match evt {
|
||||||
VirtualEvent::$eventdata(event) => callback(event),
|
VirtualEvent::$wrapper(event) => callback(event),
|
||||||
_ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!")
|
_ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!")
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@@ -99,36 +108,36 @@ pub mod on {
|
|||||||
}
|
}
|
||||||
|
|
||||||
event_directory! {
|
event_directory! {
|
||||||
ClipboardEvent: [copy cut paste];
|
ClipboardEventInner(ClipboardEvent): [copy cut paste];
|
||||||
CompositionEvent: [compositionend compositionstart compositionupdate];
|
CompositionEventInner(CompositionEvent): [compositionend compositionstart compositionupdate];
|
||||||
KeyboardEvent: [keydown keypress keyup];
|
KeyboardEventInner(KeyboardEvent): [keydown keypress keyup];
|
||||||
FocusEvent: [focus blur];
|
FocusEventInner(FocusEvent): [focus blur];
|
||||||
FormEvent: [change input invalid reset submit];
|
FormEventInner(FormEvent): [change input invalid reset submit];
|
||||||
MouseEvent: [
|
MouseEventInner(MouseEvent): [
|
||||||
click contextmenu doubleclick drag dragend dragenter dragexit
|
click contextmenu doubleclick drag dragend dragenter dragexit
|
||||||
dragleave dragover dragstart drop mousedown mouseenter mouseleave
|
dragleave dragover dragstart drop mousedown mouseenter mouseleave
|
||||||
mousemove mouseout mouseover mouseup
|
mousemove mouseout mouseover mouseup
|
||||||
];
|
];
|
||||||
PointerEvent: [
|
PointerEventInner(PointerEvent): [
|
||||||
pointerdown pointermove pointerup pointercancel gotpointercapture
|
pointerdown pointermove pointerup pointercancel gotpointercapture
|
||||||
lostpointercapture pointerenter pointerleave pointerover pointerout
|
lostpointercapture pointerenter pointerleave pointerover pointerout
|
||||||
];
|
];
|
||||||
SelectionEvent: [select];
|
SelectionEventInner(SelectionEvent): [select];
|
||||||
TouchEvent: [touchcancel touchend touchmove touchstart];
|
TouchEventInner(TouchEvent): [touchcancel touchend touchmove touchstart];
|
||||||
UIEvent: [scroll];
|
UIEventInner(UIEvent): [scroll];
|
||||||
WheelEvent: [wheel];
|
WheelEventInner(WheelEvent): [wheel];
|
||||||
MediaEvent: [
|
MediaEventInner(MediaEvent): [
|
||||||
abort canplay canplaythrough durationchange emptied encrypted
|
abort canplay canplaythrough durationchange emptied encrypted
|
||||||
ended error loadeddata loadedmetadata loadstart pause play
|
ended error loadeddata loadedmetadata loadstart pause play
|
||||||
playing progress ratechange seeked seeking stalled suspend
|
playing progress ratechange seeked seeking stalled suspend
|
||||||
timeupdate volumechange waiting
|
timeupdate volumechange waiting
|
||||||
];
|
];
|
||||||
AnimationEvent: [animationstart animationend animationiteration];
|
AnimationEventInner(AnimationEvent): [animationstart animationend animationiteration];
|
||||||
TransitionEvent: [transitionend];
|
TransitionEventInner(TransitionEvent): [transitionend];
|
||||||
ToggleEvent: [toggle];
|
ToggleEventInner(ToggleEvent): [toggle];
|
||||||
}
|
}
|
||||||
|
|
||||||
trait GenericEvent {
|
pub trait GenericEventInner {
|
||||||
/// Returns whether or not a specific event is a bubbling event
|
/// Returns whether or not a specific event is a bubbling event
|
||||||
fn bubbles(&self) -> bool;
|
fn bubbles(&self) -> bool;
|
||||||
/// Sets or returns whether the event should propagate up the hierarchy or not
|
/// Sets or returns whether the event should propagate up the hierarchy or not
|
||||||
@@ -159,15 +168,15 @@ pub mod on {
|
|||||||
fn time_stamp(&self) -> usize;
|
fn time_stamp(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ClipboardEvent: Debug {
|
pub trait ClipboardEventInner: Debug + GenericEventInner {
|
||||||
// DOMDataTransfer clipboardData
|
// DOMDataTransfer clipboardData
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CompositionEvent: Debug {
|
pub trait CompositionEventInner: Debug {
|
||||||
fn data(&self) -> String;
|
fn data(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait KeyboardEvent: Debug {
|
pub trait KeyboardEventInner: Debug {
|
||||||
fn char_code(&self) -> usize;
|
fn char_code(&self) -> usize;
|
||||||
fn ctrl_key(&self) -> bool;
|
fn ctrl_key(&self) -> bool;
|
||||||
fn key(&self) -> String;
|
fn key(&self) -> String;
|
||||||
@@ -181,15 +190,15 @@ pub mod on {
|
|||||||
fn get_modifier_state(&self, key_code: usize) -> bool;
|
fn get_modifier_state(&self, key_code: usize) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FocusEvent: Debug {
|
pub trait FocusEventInner: Debug {
|
||||||
/* DOMEventTarget relatedTarget */
|
/* DOMEventInnerTarget relatedTarget */
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FormEvent: Debug {
|
pub trait FormEventInner: Debug {
|
||||||
fn value(&self) -> String;
|
fn value(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MouseEvent: Debug {
|
pub trait MouseEventInner: Debug {
|
||||||
fn alt_key(&self) -> bool;
|
fn alt_key(&self) -> bool;
|
||||||
fn button(&self) -> i16;
|
fn button(&self) -> i16;
|
||||||
fn buttons(&self) -> u16;
|
fn buttons(&self) -> u16;
|
||||||
@@ -205,7 +214,7 @@ pub mod on {
|
|||||||
fn get_modifier_state(&self, key_code: &str) -> bool;
|
fn get_modifier_state(&self, key_code: &str) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PointerEvent: Debug {
|
pub trait PointerEventInner: Debug {
|
||||||
// Mouse only
|
// Mouse only
|
||||||
fn alt_key(&self) -> bool;
|
fn alt_key(&self) -> bool;
|
||||||
fn button(&self) -> usize;
|
fn button(&self) -> usize;
|
||||||
@@ -232,9 +241,9 @@ pub mod on {
|
|||||||
fn is_primary(&self) -> bool;
|
fn is_primary(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SelectionEvent: Debug {}
|
pub trait SelectionEventInner: Debug {}
|
||||||
|
|
||||||
pub trait TouchEvent: Debug {
|
pub trait TouchEventInner: Debug {
|
||||||
fn alt_key(&self) -> bool;
|
fn alt_key(&self) -> bool;
|
||||||
fn ctrl_key(&self) -> bool;
|
fn ctrl_key(&self) -> bool;
|
||||||
fn meta_key(&self) -> bool;
|
fn meta_key(&self) -> bool;
|
||||||
@@ -245,37 +254,37 @@ pub mod on {
|
|||||||
// touches: DOMTouchList,
|
// touches: DOMTouchList,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UIEvent: Debug {
|
pub trait UIEventInner: Debug {
|
||||||
// DOMAbstractView view
|
// DOMAbstractView view
|
||||||
fn detail(&self) -> i32;
|
fn detail(&self) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WheelEvent: Debug {
|
pub trait WheelEventInner: Debug {
|
||||||
fn delta_mode(&self) -> i32;
|
fn delta_mode(&self) -> i32;
|
||||||
fn delta_x(&self) -> i32;
|
fn delta_x(&self) -> i32;
|
||||||
fn delta_y(&self) -> i32;
|
fn delta_y(&self) -> i32;
|
||||||
fn delta_z(&self) -> i32;
|
fn delta_z(&self) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MediaEvent: Debug {}
|
pub trait MediaEventInner: Debug {}
|
||||||
|
|
||||||
pub trait ImageEvent: Debug {
|
pub trait ImageEventInner: Debug {
|
||||||
// load error
|
// load error
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AnimationEvent: Debug {
|
pub trait AnimationEventInner: Debug {
|
||||||
fn animation_name(&self) -> String;
|
fn animation_name(&self) -> String;
|
||||||
fn pseudo_element(&self) -> String;
|
fn pseudo_element(&self) -> String;
|
||||||
fn elapsed_time(&self) -> f32;
|
fn elapsed_time(&self) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TransitionEvent: Debug {
|
pub trait TransitionEventInner: Debug {
|
||||||
fn property_name(&self) -> String;
|
fn property_name(&self) -> String;
|
||||||
fn pseudo_element(&self) -> String;
|
fn pseudo_element(&self) -> String;
|
||||||
fn elapsed_time(&self) -> f32;
|
fn elapsed_time(&self) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToggleEvent: Debug {}
|
pub trait ToggleEventInner: Debug {}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|||||||
@@ -768,6 +768,25 @@ impl<'a> NodeFactory<'a> {
|
|||||||
> {
|
> {
|
||||||
ElementBuilder::new(self, tag_name)
|
ElementBuilder::new(self, tag_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn child_list(&self) -> ChildrenList {
|
||||||
|
ChildrenList::new(&self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fragment_builder<'b>(
|
||||||
|
&'b self,
|
||||||
|
key: Option<&'a str>,
|
||||||
|
builder: impl FnOnce(ChildrenList<'a, 'b>) -> &'a [VNode<'a>],
|
||||||
|
) -> VNode<'a> {
|
||||||
|
self.fragment(builder(ChildrenList::new(&self)), key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fragment(&self, children: &'a [VNode<'a>], key: Option<&'a str>) -> VNode<'a> {
|
||||||
|
VNode::Fragment(self.bump().alloc(VFragment {
|
||||||
|
children,
|
||||||
|
key: NodeKey::new_opt(key),
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|||||||
@@ -297,6 +297,11 @@ impl<'a> NodeKey<'a> {
|
|||||||
pub fn new(key: &'a str) -> Self {
|
pub fn new(key: &'a str) -> Self {
|
||||||
NodeKey(Some(key))
|
NodeKey(Some(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new_opt(key: Option<&'a str>) -> Self {
|
||||||
|
NodeKey(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|||||||
Reference in new issue
Block a user